From 01f2fe275b3b7a9a6f5805e0f69546159644ae94 Mon Sep 17 00:00:00 2001 From: Jowitt13 <51783594+Jowitt13@users.noreply.github.com> Date: Thu, 30 Jul 2026 18:04:45 +0800 Subject: [PATCH 1/2] docs(vedic): scope P2 cross-check evidence by field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep Swiss -sid1 external goldens as the ≤1′ hard gate while recording MIT cross-checks only for fields they demonstrably cover. Record the NDAstro 0.28.1 audit: Sun..Saturn and mean Rahu pre-screen pass; true Rahu and Lagna fail and remain Swiss-only external numeric references. Raise P2's synthetic-case minimum to 100 and pin disclosure/invariant safeguards with a doc gate. No calculation, contract, lockfile, SBOM, bundle or golden changes. --- docs/STATUS.md | 2 +- docs/VALIDATION.md | 2 +- docs/VEDIC_SOURCE_MATRIX.md | 25 ++++++++++++++--- docs/adr/0013-vedic-architecture.md | 43 ++++++++++++++++++++++++++--- tools/vedic-docs.test.ts | 14 ++++++++++ 5 files changed, 76 insertions(+), 10 deletions(-) diff --git a/docs/STATUS.md b/docs/STATUS.md index 6d459f7..1ae05d1 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -179,7 +179,7 @@ never by hand. | Command | Result | | ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `pnpm run typecheck` | clean (tsc strict over packages, tools, tests) | -| `pnpm run test` | 704 tests / 38 files ?all passing (all systems + JPL Horizons 独立 golden + interpret + 吉凶 + 合婚 + reading-lint/空话/重复/越界 + validate-answer v2 结构与措辞门禁(约束引用事实豁免+全可见文本安全扫?资源上限+有界解析入口,非语义正确性证明) + western-rules/ziwei-rules 语义规则 + 版本迁移/回滚/目标白名?+ PII 隐私护栏 green) | +| `pnpm run test` | 705 tests / 38 files ?all passing (all systems + JPL Horizons 独立 golden + interpret + 吉凶 + 合婚 + reading-lint/空话/重复/越界 + validate-answer v2 结构与措辞门禁(约束引用事实豁免+全可见文本安全扫?资源上限+有界解析入口,非语义正确性证明) + western-rules/ziwei-rules 语义规则 + 版本迁移/回滚/目标白名?+ PII 隐私护栏 green) | | `pnpm run build` | `engine.mjs` ?2.8 MB + `sbom.cdx.json` + `sbom.spdx.json` (6 runtime deps) | | `pnpm run validate:skill` | 40 / 40 (incl. scripts/ no-stray-files guard + CycloneDX/SPDX SBOM checks + validate-answer/lint-reading gate-workflow doc checks) | | `pnpm run validate:reading` | 53 / 53 (topic example libraries + output-spec structure + 无术语区 firewall; offline, no LLM) | diff --git a/docs/VALIDATION.md b/docs/VALIDATION.md index 3f77c2a..9df8189 100644 --- a/docs/VALIDATION.md +++ b/docs/VALIDATION.md @@ -59,7 +59,7 @@ the identical table in [STATUS.md](./STATUS.md) ("Commands & results"). Do not h resolve a disagreement; re-run the suite and copy the actual count. `pnpm run check:doc-counts` re-runs the suite and fails if either doc's `N tests / M files` count drifts from the real run. -- Typecheck: clean. Tests: **704 tests / 38 files ?all passing**. The Western provider +- Typecheck: clean. Tests: **705 tests / 38 files ?all passing**. The Western provider (astronomy-engine, VSOP87 + NOVAS) passes the ADR-0003 ??gate two ways: wrapper-consistency (vs astronomy-engine's own output) plus an **independent JPL Horizons golden** (10 bodies × 3 technical epochs fetched from the NASA/JPL Horizons service, query recorded in diff --git a/docs/VEDIC_SOURCE_MATRIX.md b/docs/VEDIC_SOURCE_MATRIX.md index 2dec27b..6ba242c 100644 --- a/docs/VEDIC_SOURCE_MATRIX.md +++ b/docs/VEDIC_SOURCE_MATRIX.md @@ -76,11 +76,28 @@ Acceptable error | Unresolved questions** - Captured with the existing two-phase isolated workflow (staging dir → atomic rename → SHA-256 manifest of every stdout/stderr/argv → reviewed transcription). swetest binaries and ephemeris files never enter the repo; `.tmp` capture dirs stay untracked. -- Cross-verification: Swiss (`-sid1`) is the primary reference; at least one independent MIT - implementation (jyotishganit candidate) is recorded **per-source** in the fixture. Any - disagreement above tolerance is preserved and investigated — never resolved by majority vote. +- Cross-verification: Swiss (`-sid1`) is the hard primary reference. Independent MIT results are + recorded **per field only where they demonstrably pass**; any disagreement above tolerance is + preserved and investigated — never resolved by majority vote. A field without such a passing + cross-check is explicitly disclosed as a Swiss-only external numeric reference. - Gate: grahas, nodes (both modes) and Lagna ≤1 arc-minute; Ketu opposition exact; derived - classifications must match the classification of the golden longitude. + classifications must match the classification of the golden longitude. The minimum matrix is + **100 synthetic cases** (this supersedes the earlier 50-case planning minimum). + +### P2 validation-evidence amendment (2026-07-30) + +The following audit record narrows the meaning of “second source” without lowering the Swiss +numeric gate. It is a source-audit record only: it adds no Vedic code, fixture or precision claim. + +| Candidate | Audit outcome | Fields usable as supplementary evidence | Fields explicitly not covered | Binding consequence | +| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| NDAstro 0.28.1 (MIT; Skyfield/JPL) | Wheel and fixed `v0.28.1` tag sources matched byte-for-byte; no Swiss runtime import; ordinary `lahiri` pre-screened against `swetest -sid1 -utc -emos` across 11 synthetic cases / 110 comparisons | Sun..Saturn (worst 0.710′); mean Rahu (worst 0.046′) | true Rahu (worst 7.633′); Lagna (worst 10.286′) | **REJECTED_FOR_MODE1_REFERENCE** as a full oracle. It may be recorded only for passing fields; true Rahu and Lagna remain Swiss-only external numeric references until another source passes them. | + +For every Swiss-only field, the P2 fixture must carry the raw-capture argv, `swetest` version, +stdout/stderr SHA-256 manifest and reviewed transcription trail. P2 adds Ketu opposition, +true-node continuity/no-boundary-jump and Lagna tropical-to-sidereal transform assertions. These +checks detect implementation and fixture wiring errors; they are not presented as a second +independent astronomical implementation. ## Blocked items diff --git a/docs/adr/0013-vedic-architecture.md b/docs/adr/0013-vedic-architecture.md index 5315f0b..7af10bc 100644 --- a/docs/adr/0013-vedic-architecture.md +++ b/docs/adr/0013-vedic-architecture.md @@ -286,10 +286,45 @@ decision (§Open questions); the engine capability does not depend on it. the isolated two-phase `swetest -sid1` workflow (staging dir → SHA-256 manifest → reviewed transcription; binaries/ephemeris files never enter the repo), gate ≤1′ for grahas, nodes and Lagna; Rahu/Ketu opposition asserted; cross-checked against at least one independent MIT - implementation (candidate: jyotishganit, Python/Skyfield/JPL) — discrepancies are **recorded - per-source in the fixture, never majority-voted away**. All inputs marked synthetic. - **Blocker carried into P2/P3**: pin the sunrise backend parameter mapping (§9) with sunrise - spot-check goldens before any Vaara output. + implementation where one is available — discrepancies are **recorded per-source in the fixture, + never majority-voted away**. The field-scoped evidence policy below is binding. All inputs marked + synthetic. **Blocker carried into P2/P3**: pin the sunrise backend parameter mapping (§9) with + sunrise spot-check goldens before any Vaara output. + +### P2 verification evidence boundary (amended 2026-07-30) + +This amendment supersedes the generic all-fields independent-MIT wording in the P2 bullet above. +It does **not** lower any numerical acceptance threshold. + +1. **Swiss remains the hard acceptance oracle for every P2 numeric field.** The implementation + must match reviewed, isolated `swetest -sid1 -utc -emos` fixtures within ≤1′ for every graha, + both Rahu modes and Lagna; Ketu remains an exact opposition invariant. A passing result may be + described only as “matches the recorded Swiss fixtures within ≤1′”, never as a general claim of + physical or absolute astrometric accuracy. +2. **MIT cross-checks are field-scoped supplementary evidence, not a substitute oracle.** A + passing independent MIT implementation is recorded for the individual fields it demonstrably + covers. Its absence or failure for another field never relaxes the Swiss gate; that field is + explicitly marked **Swiss-only external numeric reference** in the fixture and public + provenance notes. No majority vote is allowed. +3. **NDAstro 0.28.1 audit record.** Its MIT wheel and tag `v0.28.1` sources were byte-for-byte + bound; its Skyfield/JPL route contains no Swiss runtime dependency. Against 11 synthetic cases + (110 comparisons) using ordinary `lahiri` only — never its mode-43-compatible + `true_lahiri` / `lahiri_traditional` paths — it passed Sun..Saturn (worst 0.710′) and mean + Rahu (worst 0.046′). It failed true Rahu (worst 7.633′) and Lagna (worst 10.286′), so it is + **REJECTED_FOR_MODE1_REFERENCE** as a full P2 oracle. It is retained only as supplementary + pre-screen evidence for the fields that passed; it is never embedded, copied or made a runtime + dependency. +4. **Compensating Swiss-only safeguards.** P2 now requires at least **100 synthetic cases**, + including the stated multi-decade, hemisphere, IANA-zone and classification-boundary coverage. + Each capture must retain the exact argv, `swetest` version, raw stdout/stderr SHA-256 manifest + and reviewed transcription trail outside the repository. True-node tests additionally assert + Ketu opposition, continuity and no boundary jump; Lagna tests assert the explicit tropical-to- + sidereal transform and the existing high-latitude contract. These are implementation checks, + not a claim of a second independent ephemeris. + +Until a future independent source passes a field, user-facing and release documentation must say +“Swiss-only external numeric reference” for that field and must not claim two-source validation. + - **P3 — classifications**: Rashi/Bhava/Nakshatra/Pada/Panchanga/D1/D9/Vimshottari per §§7–12, including boundary-case unit tests on both sides of every segment edge. **Blocked until** the Vimshottari year-model owner decision + same-model dual-implementation cross-check (§11) and diff --git a/tools/vedic-docs.test.ts b/tools/vedic-docs.test.ts index 7cf255f..7f2c168 100644 --- a/tools/vedic-docs.test.ts +++ b/tools/vedic-docs.test.ts @@ -56,6 +56,20 @@ describe('vedic docs gate: P0 deliverables present and complete', () => { expect(adr).toMatch(/not yet verified and is a P2\/P3\s+implementation blocker/i); }); + it('keeps the P2 evidence amendment field-scoped without lowering the Swiss gate', () => { + const adr = read(ADR); + const matrix = read(MATRIX); + for (const text of [adr, matrix]) { + expect(text).toContain('Swiss-only external numeric reference'); + expect(text).toContain('100 synthetic cases'); + expect(text).toContain('REJECTED_FOR_MODE1_REFERENCE'); + } + expect(adr).toContain('worst 7.633′'); + expect(adr).toContain('worst 10.286′'); + expect(adr).toMatch(/Swiss remains the hard acceptance oracle/i); + expect(adr).toMatch(/never as a general claim of[\s\S]*accuracy/i); + }); + it('source matrix exists with the ten required columns and license boundary', () => { const matrix = read(MATRIX); const requiredColumns = [ From 55e8cc404e9196c8685d45c5d67c18d077dc5967 Mon Sep 17 00:00:00 2001 From: Jowitt13 <51783594+Jowitt13@users.noreply.github.com> Date: Fri, 31 Jul 2026 00:49:23 +0800 Subject: [PATCH 2/2] docs(vedic): confirm dasha and sunrise defaults Record the two owner decisions of 2026-07-31 in ADR 0013 and its companions: the Vimshottari year model is fixed to dashaYear 'julian-365.25' (365.25 x 86400 SI seconds; savana-360/sidereal only as future new rulesets) and the Vaara sunrise rule is fixed to upper-limb + standard 34-arcmin refraction (upper-limb-standard-refraction). Both remain delivery-gated by verification evidence only: Vimshottari by the same-model dual-implementation cross-check, Vaara by the sunrise backend-mapping goldens (the -50-arcmin center mapping stays a P2/P3 implementation blocker). ADR Status stays Proposed because the Rahu node default is still awaiting owner confirmation. Open questions 2 and 3 are marked Resolved 2026-07-31; Consequences now separates frozen owner defaults from outstanding verification gates. vedic-docs.test.ts locks the new semantics without relaxing any capability-claim or precision gate. Docs only; no contracts, lockfile, SBOM, bundle, golden, Skill, manifest or release changes (verified zero diff). --- docs/RULESETS.md | 15 +++--- docs/VEDIC_SOURCE_MATRIX.md | 67 +++++++++++++------------- docs/adr/0013-vedic-architecture.md | 75 +++++++++++++++++------------ tools/vedic-docs.test.ts | 21 +++++--- 4 files changed, 102 insertions(+), 76 deletions(-) diff --git a/docs/RULESETS.md b/docs/RULESETS.md index 6042d71..6210255 100644 --- a/docs/RULESETS.md +++ b/docs/RULESETS.md @@ -44,12 +44,15 @@ Roadmap only — **no Vedic calculation exists in the engine today** and no user claim otherwise until the ADR 0013 P5 slice ships. P1 status: the contracts reserve the `vedic` system id (`VedicSettings`/`VedicChartResult`, opt-in only — the default `systems` array stays three-system) and `@ming/vedic` / `@ming/vedic-rules` exist as skeletons whose provider always -returns `SYSTEM_NOT_YET_IMPLEMENTED`; nothing is computed and no defaults are wired for the -unresolved knobs (`nodes`, `dashaYear`). The frozen engineering boundaries (Lahiri = -IAE-1985 standard / Swiss `SE_SIDM_LAHIRI`, Ketu = Rahu+180°, whole-sign bhava, 27-nakshatra -scheme, instantaneous panchanga, D1/D9) plus the proposed-but-unconfirmed defaults (mean Rahu; -upper-limb sunrise target; Vimshottari year model **candidate `julian-365.25` — P3 -implementation blocked on the owner decision and a same-model dual-implementation cross-check**) +returns `SYSTEM_NOT_YET_IMPLEMENTED`; the engine skeleton still computes no Vedic data at all. +Owner-confirmed defaults (2026-07-31): the Vimshottari year model is +`dashaYear: 'julian-365.25'` (365.25 × 86400 SI seconds; savana-360/sidereal only as future new +rulesets) and the Vaara sunrise rule is `upper-limb-standard-refraction` (upper limb + standard +34′ refraction). Still undecided: the Rahu node default (`nodes`). Delivery gates remain: +Vimshottari cannot ship before its same-model (`julian-365.25`) dual-implementation cross-check +passes, and Vaara cannot ship before the sunrise backend-mapping goldens pass. The frozen +engineering boundaries (Lahiri = IAE-1985 standard / Swiss `SE_SIDM_LAHIRI`, Ketu = Rahu+180°, +whole-sign bhava, 27-nakshatra scheme, instantaneous panchanga, D1/D9) live in [ADR 0013](adr/0013-vedic-architecture.md) and the per-topic source registry [`docs/VEDIC_SOURCE_MATRIX.md`](VEDIC_SOURCE_MATRIX.md). Target product version: v0.3.0. diff --git a/docs/VEDIC_SOURCE_MATRIX.md b/docs/VEDIC_SOURCE_MATRIX.md index 6ba242c..9e7a801 100644 --- a/docs/VEDIC_SOURCE_MATRIX.md +++ b/docs/VEDIC_SOURCE_MATRIX.md @@ -35,30 +35,30 @@ Acceptable error | Unresolved questions** ### Astronomical layer -| Topic | Adopted definition | Primary source | Secondary cross-source | School disagreement | License status | Future implementation file | External golden method | Acceptable error | Unresolved questions | -| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------ | --------------------------------------------------------------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | -| Ayanamsha (Lahiri) | True (nutation-included) ayanamsha, 23°15′00″.658 at 1956-03-21 00:00 TDT, per IAE 1985+ / Rashtriya Panchang; = Swiss `SE_SIDM_LAHIRI` (mode 1) | Swiss Ephemeris doc §2.8.5 + Appendix E (IAE comparison); IAE itself | jyotishganit Lahiri output; VedAstro API | True Chitra Paksha (mode 27) and Lahiri ICRC (mode 46) are distinct, rejected as defaults | Definition = public factual data; Swiss used doc-only | `packages/vedic/src/ayanamsha.ts` | `swetest -sid1` isolated capture, 1900–2100 sweep | ≤1′ vs Swiss over support window | Exact in-house polynomial choice (P2); behavior at window edges | -| Graha positions (Sun..Saturn) | Geocentric apparent ecliptic-of-date (light-time + aberration), then − ayanamsha | astronomy-engine (VSOP87+NOVAS); Meeus for method background | JPL Horizons (existing tropical golden), Swiss sidereal golden | Some almanacs quote true geometric instead of apparent; drik practice = apparent | astronomy-engine MIT (bundled) | `packages/vedic/src/grahas.ts` (reusing `western/src/ephemeris.ts` primitives) | `swetest -sid1 -p0..6` per case | ≤1′ | None known | -| Rahu (mean) | Mean lunar node, uniformly regressing | Meeus ch. 47 mean-node series; Swiss doc §2.2.1 (mean node provenance) | Swiss `swetest -pm`; jyotishganit | Mean vs true is a live school split (KP tradition mean; several modern tools true) | MIT-clean (own series) | `packages/vedic/src/nodes.ts` | `swetest -sid1 -pm` | ≤1′ | Whether existing `western/src/ephemeris.ts` Meeus series passes ≤1′ as-is (verify, then share) | -| Rahu (true) | Osculating node of the momentary lunar orbit (traditional ecliptic-plane version) | Swiss doc §2.2.2 (The True Node) | Swiss `swetest -pt`; jyotishganit | Same split as above; oscillates around mean | MIT-clean (own construction) | `packages/vedic/src/nodes.ts` | `swetest -sid1 -pt` | ≤1′ | Current Western osculating construction is `approximate`; may need refinement to hold ≤1′ | -| Ketu | Rahu + 180° exactly (both node modes) | Universal convention; BPHS graha chapters treat Rahu/Ketu as the two nodes | Swiss golden (opposition asserted per sample) | None | — | `packages/vedic/src/nodes.ts` | Opposition property test on every golden row | Exact (mod rounding) | None | -| Lagna (sidereal ascendant) | Tropical apparent ascendant (existing Swiss-verified angles path) − ayanamsha | Existing `packages/western/src/houses.ts` ASC (v0.2.0 house golden) | `swetest -sid1 -house` ASC | None on definition; precision differences only | MIT | `packages/vedic/src/lagna.ts` | `swetest -sid1` house call per case | ≤1′ | High-latitude behavior documented (ASC always defined; no quadrant cusps needed for whole-sign) | -| Time scales (UTC↔TT, ΔT) | UTC instant from existing normalization; ΔT internal to astronomy-engine | astronomy-engine docs; Swiss doc ch. 7 (ΔT) as comparison background | Golden residuals absorb model deltas | None (engineering topic) | MIT | existing `packages/time-location` (unchanged) | Implicit in every golden comparison | Within the ≤1′ budget | If ΔT delta ever dominates residual, revisit | -| Sunrise (for Vaara) | Upper-limb rule target (proposed); installed-backend evidence (astronomy-engine 2.1.19 `astronomy.js`: top-edge rise semantics, apparent angular radius applied, fixed 34′ refraction); exact mapping to the classical −50′ center convention **unverified — P2/P3 blocker** | astronomy-engine 2.1.19 source (node_modules inspection); Meeus ch. 15 for rise/set background | Drik Panchang settings page documents "Edges" vs "Middle Limb" conventions | Hindu panchangas split between upper-limb and disc-center (± ~1–2 min) | MIT | `packages/vedic/src/panchanga.ts` | Sunrise spot-check goldens must pin the parameter mapping before any Vaara output | ≤1 min for Vaara boundary purposes | Owner confirmation of upper-limb target; backend mapping verification (P2); elevation ignored in v1 (caveat); disc-center variant deferred | +| Topic | Adopted definition | Primary source | Secondary cross-source | School disagreement | License status | Future implementation file | External golden method | Acceptable error | Unresolved questions | +| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------ | --------------------------------------------------------------------------------- | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------- | +| Ayanamsha (Lahiri) | True (nutation-included) ayanamsha, 23°15′00″.658 at 1956-03-21 00:00 TDT, per IAE 1985+ / Rashtriya Panchang; = Swiss `SE_SIDM_LAHIRI` (mode 1) | Swiss Ephemeris doc §2.8.5 + Appendix E (IAE comparison); IAE itself | jyotishganit Lahiri output; VedAstro API | True Chitra Paksha (mode 27) and Lahiri ICRC (mode 46) are distinct, rejected as defaults | Definition = public factual data; Swiss used doc-only | `packages/vedic/src/ayanamsha.ts` | `swetest -sid1` isolated capture, 1900–2100 sweep | ≤1′ vs Swiss over support window | Exact in-house polynomial choice (P2); behavior at window edges | +| Graha positions (Sun..Saturn) | Geocentric apparent ecliptic-of-date (light-time + aberration), then − ayanamsha | astronomy-engine (VSOP87+NOVAS); Meeus for method background | JPL Horizons (existing tropical golden), Swiss sidereal golden | Some almanacs quote true geometric instead of apparent; drik practice = apparent | astronomy-engine MIT (bundled) | `packages/vedic/src/grahas.ts` (reusing `western/src/ephemeris.ts` primitives) | `swetest -sid1 -p0..6` per case | ≤1′ | None known | +| Rahu (mean) | Mean lunar node, uniformly regressing | Meeus ch. 47 mean-node series; Swiss doc §2.2.1 (mean node provenance) | Swiss `swetest -pm`; jyotishganit | Mean vs true is a live school split (KP tradition mean; several modern tools true) | MIT-clean (own series) | `packages/vedic/src/nodes.ts` | `swetest -sid1 -pm` | ≤1′ | Whether existing `western/src/ephemeris.ts` Meeus series passes ≤1′ as-is (verify, then share) | +| Rahu (true) | Osculating node of the momentary lunar orbit (traditional ecliptic-plane version) | Swiss doc §2.2.2 (The True Node) | Swiss `swetest -pt`; jyotishganit | Same split as above; oscillates around mean | MIT-clean (own construction) | `packages/vedic/src/nodes.ts` | `swetest -sid1 -pt` | ≤1′ | Current Western osculating construction is `approximate`; may need refinement to hold ≤1′ | +| Ketu | Rahu + 180° exactly (both node modes) | Universal convention; BPHS graha chapters treat Rahu/Ketu as the two nodes | Swiss golden (opposition asserted per sample) | None | — | `packages/vedic/src/nodes.ts` | Opposition property test on every golden row | Exact (mod rounding) | None | +| Lagna (sidereal ascendant) | Tropical apparent ascendant (existing Swiss-verified angles path) − ayanamsha | Existing `packages/western/src/houses.ts` ASC (v0.2.0 house golden) | `swetest -sid1 -house` ASC | None on definition; precision differences only | MIT | `packages/vedic/src/lagna.ts` | `swetest -sid1` house call per case | ≤1′ | High-latitude behavior documented (ASC always defined; no quadrant cusps needed for whole-sign) | +| Time scales (UTC↔TT, ΔT) | UTC instant from existing normalization; ΔT internal to astronomy-engine | astronomy-engine docs; Swiss doc ch. 7 (ΔT) as comparison background | Golden residuals absorb model deltas | None (engineering topic) | MIT | existing `packages/time-location` (unchanged) | Implicit in every golden comparison | Within the ≤1′ budget | If ΔT delta ever dominates residual, revisit | +| Sunrise (for Vaara) | **Owner-confirmed (2026-07-31): upper-limb + standard 34′ refraction (`upper-limb-standard-refraction`)**; installed-backend evidence (astronomy-engine 2.1.19 `astronomy.js`: top-edge rise semantics, apparent angular radius applied, fixed 34′ refraction); exact mapping to the classical −50′ center convention **unverified — P2/P3 blocker** | astronomy-engine 2.1.19 source (node_modules inspection); Meeus ch. 15 for rise/set background | Drik Panchang settings page documents "Edges" vs "Middle Limb" conventions | Hindu panchangas split between upper-limb and disc-center (± ~1–2 min) | MIT | `packages/vedic/src/panchanga.ts` | Sunrise spot-check goldens must pin the parameter mapping before any Vaara output | ≤1 min for Vaara boundary purposes | Backend mapping verification (P2); elevation ignored in v1 (caveat); disc-center variant deferred to a future ruleset | ### Classification layer (traditional rules on top of the numbers) -| Topic | Adopted definition | Primary source | Secondary cross-source | School disagreement | License status | Future implementation file | External golden method | Acceptable error | Unresolved questions | -| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | -------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | -| Rashi (D1) | 12 × 30° from sidereal 0° Aries; `floor(λ_sid/30)`; [start,end) | BPHS rashi chapters; universal | Swiss (sign of sidereal longitude); jyotishganit | None | Public domain rule | `packages/vedic/src/rashi.ts` | Derived from graha golden (sign of golden longitude) | Exact given ≤1′ longitudes; near-boundary caveat <1′ | None | -| Whole-sign bhava | Bhava n = n-th rashi from Lagna rashi | BPHS bhava chapters (whole-sign as base scheme) | PyJHora feature list (research-only) confirms as standard option | Bhava Chalit / Sripati widely used for _bhava madhya_; out of scope v1, structured warning | Public domain rule | `packages/vedic/src/bhava.ts` | Derived from Lagna golden | Exact given Lagna | Chalit semantics for a future ruleset | -| Nakshatra + Pada | 27 × 13°20′ from sidereal 0° Aries; pada = 3°20′ quarters; [start,end) | BPHS nakshatra enumeration; Vimshottari chapter implies 27-scheme | Swiss golden longitudes → derived; drik panchang tables | 28-nakshatra (Abhijit) scheme exists; out of scope v1 | Public domain rule | `packages/vedic/src/nakshatra.ts` | Derived from Moon golden incl. boundary-straddling cases | Exact given ≤1′; near-boundary caveat | None | -| Tithi | `floor(Δλ/12°)+1`, 1..30; ayanamsha-invariant | Surya Siddhanta elongation definition; universal panchanga practice | drik panchang published values; jyotishganit | None on formula; only sunrise-day _assignment_ differs (we emit instantaneous) | Public domain rule | `packages/vedic/src/panchanga.ts` | Derived from Sun/Moon golden; boundary cases | Exact given ≤1′ | None | -| Yoga (nityayoga) | `floor((λ_sid_moon + λ_sid_sun)/13°20′)+1`, 1..27 | Standard panchanga definition (Surya Siddhanta tradition) | drik panchang values; jyotishganit | None on formula; **sum is ayanamsha-sensitive** (classic bug source, golden-covered) | Public domain rule | `packages/vedic/src/panchanga.ts` | Derived from golden sidereal longitudes | Exact given ≤1′ | None | -| Karana | `floor(Δλ/6°)`, 0..59; 0=Kimstughna fixed; 1..56 = 7 movable ×8; 57..59 = Shakuni/Chatushpada/Naga | Standard panchanga definition | drik panchang values | None material | Public domain rule | `packages/vedic/src/panchanga.ts` | Derived from golden | Exact given ≤1′ | None | -| Vaara | Weekday from local sunrise to next sunrise | Universal panchanga convention | drik panchang day pages | Sunrise definition split (see astronomical layer) | Public domain rule | `packages/vedic/src/panchanga.ts` | Sunrise spot-checks + boundary tests (birth just before/after sunrise) | Correct weekday except within sunrise-model delta (~2 min, caveated) | None beyond sunrise model | -| Navamsha (D9) | 9 × 3°20′ per rashi; count from self (movable) / 9th (fixed) / 5th (dual); [start,end) | BPHS varga (Saptavarga/Shodashavarga) chapters | jyotishganit D9; VedAstro D9; equivalence check of the two standard formulations | Minor traditions vary on varga counting for other vargas, not D9 | Public domain rule | `packages/vedic/src/varga.ts` | Cross-check D9 sign per golden case vs jyotishganit (recorded per-source, no majority vote) | Exact given ≤1′; near-boundary caveat | None | -| Vimshottari Maha/Antar | Ketu7 Venus20 Sun6 Moon10 Mars7 Rahu18 Jupiter16 Saturn19 Mercury17 (120y); start = Moon-nakshatra lord; balance = remaining arc fraction × lord years; antar ∝ years/120 from Maha lord; [start,end) | BPHS Vimshottari dasha chapter | jyotishganit dasha dates; VedAstro | **Year length: BLOCKED / owner decision.** Candidate: `julian-365.25`; alternatives savana-360 (≈630 days shorter per 120y) and sidereal year (≈+46 days per 120y vs julian); no product default may be wired before the decision | Public domain rule | `packages/vedic/src/vimshottari.ts` | Recompute dasha dates from golden Moon longitude; cross-check jyotishganit configured to the **identical year model** (same-model comparison mandatory) | Start/balance exact given ≤1′ Moon; date drift ≤1 day per 120y vs same-model reference | **BLOCKED**: owner year-model decision + dual-implementation same-model cross-check gate P3 | +| Topic | Adopted definition | Primary source | Secondary cross-source | School disagreement | License status | Future implementation file | External golden method | Acceptable error | Unresolved questions | +| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------ | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | +| Rashi (D1) | 12 × 30° from sidereal 0° Aries; `floor(λ_sid/30)`; [start,end) | BPHS rashi chapters; universal | Swiss (sign of sidereal longitude); jyotishganit | None | Public domain rule | `packages/vedic/src/rashi.ts` | Derived from graha golden (sign of golden longitude) | Exact given ≤1′ longitudes; near-boundary caveat <1′ | None | +| Whole-sign bhava | Bhava n = n-th rashi from Lagna rashi | BPHS bhava chapters (whole-sign as base scheme) | PyJHora feature list (research-only) confirms as standard option | Bhava Chalit / Sripati widely used for _bhava madhya_; out of scope v1, structured warning | Public domain rule | `packages/vedic/src/bhava.ts` | Derived from Lagna golden | Exact given Lagna | Chalit semantics for a future ruleset | +| Nakshatra + Pada | 27 × 13°20′ from sidereal 0° Aries; pada = 3°20′ quarters; [start,end) | BPHS nakshatra enumeration; Vimshottari chapter implies 27-scheme | Swiss golden longitudes → derived; drik panchang tables | 28-nakshatra (Abhijit) scheme exists; out of scope v1 | Public domain rule | `packages/vedic/src/nakshatra.ts` | Derived from Moon golden incl. boundary-straddling cases | Exact given ≤1′; near-boundary caveat | None | +| Tithi | `floor(Δλ/12°)+1`, 1..30; ayanamsha-invariant | Surya Siddhanta elongation definition; universal panchanga practice | drik panchang published values; jyotishganit | None on formula; only sunrise-day _assignment_ differs (we emit instantaneous) | Public domain rule | `packages/vedic/src/panchanga.ts` | Derived from Sun/Moon golden; boundary cases | Exact given ≤1′ | None | +| Yoga (nityayoga) | `floor((λ_sid_moon + λ_sid_sun)/13°20′)+1`, 1..27 | Standard panchanga definition (Surya Siddhanta tradition) | drik panchang values; jyotishganit | None on formula; **sum is ayanamsha-sensitive** (classic bug source, golden-covered) | Public domain rule | `packages/vedic/src/panchanga.ts` | Derived from golden sidereal longitudes | Exact given ≤1′ | None | +| Karana | `floor(Δλ/6°)`, 0..59; 0=Kimstughna fixed; 1..56 = 7 movable ×8; 57..59 = Shakuni/Chatushpada/Naga | Standard panchanga definition | drik panchang values | None material | Public domain rule | `packages/vedic/src/panchanga.ts` | Derived from golden | Exact given ≤1′ | None | +| Vaara | Weekday from local sunrise to next sunrise | Universal panchanga convention | drik panchang day pages | Sunrise definition split (see astronomical layer) | Public domain rule | `packages/vedic/src/panchanga.ts` | Sunrise spot-checks + boundary tests (birth just before/after sunrise) | Correct weekday except within sunrise-model delta (~2 min, caveated) | None beyond sunrise model | +| Navamsha (D9) | 9 × 3°20′ per rashi; count from self (movable) / 9th (fixed) / 5th (dual); [start,end) | BPHS varga (Saptavarga/Shodashavarga) chapters | jyotishganit D9; VedAstro D9; equivalence check of the two standard formulations | Minor traditions vary on varga counting for other vargas, not D9 | Public domain rule | `packages/vedic/src/varga.ts` | Cross-check D9 sign per golden case vs jyotishganit (recorded per-source, no majority vote) | Exact given ≤1′; near-boundary caveat | None | +| Vimshottari Maha/Antar | Ketu7 Venus20 Sun6 Moon10 Mars7 Rahu18 Jupiter16 Saturn19 Mercury17 (120y); start = Moon-nakshatra lord; balance = remaining arc fraction × lord years; antar ∝ years/120 from Maha lord; [start,end) | BPHS Vimshottari dasha chapter | jyotishganit dasha dates; VedAstro | **Year length: Owner-confirmed (2026-07-31) `dashaYear: 'julian-365.25'`** (dasha year = 365.25 × 86400 SI seconds); savana-360 (≈630 days shorter per 120y) and sidereal year (≈+46 days per 120y vs julian) ship only as future new ruleset versions | Public domain rule | `packages/vedic/src/vimshottari.ts` | Recompute dasha dates from golden Moon longitude; cross-check a second independent implementation configured to the **identical `julian-365.25` model** (same-model comparison mandatory) | Start/balance exact given ≤1′ Moon; date drift ≤1 day per 120y vs same-model reference | Only remaining gate: same-model dual-implementation cross-check before P3 dasha ships | ### Output / product layer @@ -99,18 +99,19 @@ true-node continuity/no-boundary-jump and Lagna tropical-to-sidereal transform a checks detect implementation and fixture wiring errors; they are not presented as a second independent astronomical implementation. -## Blocked items +## Remaining verification blockers -Two items are **BLOCKED at P0 close** (owner decision / verification evidence, not a missing -source): +Both items below are **evidence gates, not missing owner decisions** — the owner defaults were +confirmed 2026-07-31 and are recorded in ADR 0013: -1. **Vimshottari year model** — candidate `julian-365.25`; the P3 dasha implementation is - blocked on the owner decision plus a same-model cross-check against a second independent - implementation. P1 may reserve the versioned enum but must not wire any value as the product - default. -2. **Sunrise backend parameter mapping** — rule target is upper-limb (proposed); astronomy-engine - 2.1.19's documented behavior (top-edge + angular radius + fixed 34′ refraction) still needs - P2 golden verification before any Vaara output ships. +1. **Vimshottari same-model cross-check** — the default is owner-confirmed + `dashaYear: 'julian-365.25'`; the P3 dasha implementation still cannot ship until it passes a + cross-check against a second independent implementation configured to the identical + `julian-365.25` model. +2. **Sunrise backend parameter mapping** — the rule is owner-confirmed + `upper-limb-standard-refraction`; astronomy-engine 2.1.19's documented behavior (top-edge + + angular radius + fixed 34′ refraction) still needs P2 sunrise spot-check golden verification + against the classical −50′ convention before any Vaara output ships. -All other conventions have at least one authoritative primary source. Remaining items awaiting -an **owner decision** are listed in ADR 0013 "Open questions". +All other conventions have at least one authoritative primary source. The remaining item awaiting +an **owner decision** (the Rahu node default) is listed in ADR 0013 "Open questions". diff --git a/docs/adr/0013-vedic-architecture.md b/docs/adr/0013-vedic-architecture.md index 7af10bc..d673f14 100644 --- a/docs/adr/0013-vedic-architecture.md +++ b/docs/adr/0013-vedic-architecture.md @@ -1,10 +1,12 @@ # ADR 0013: Vedic (Jyotish) system architecture & rule-convention freeze (P0) -- Status: Proposed — P0 architecture complete; semantic defaults awaiting owner confirmation - (**no Vedic code exists yet — nothing below is implemented**). Engineering boundaries in - §§1–4, 6–10, 12–16 are frozen; the node default (§5), the sunrise backend mapping (§9) and - the Vimshottari year model (§11) are proposed/blocked pending the owner decisions listed under - "Open questions". +- Status: Proposed — P0 architecture complete; only the Rahu node default (§5) still awaits + owner confirmation (**no Vedic code exists yet — nothing below is implemented**). + Engineering boundaries in §§1–4, 6–10, 12–16 are frozen. The sunrise rule target (§9) and + the Vimshottari year model (§11) are **owner-confirmed defaults (2026-07-31) with remaining + verification gates**: each still carries an evidence gate (sunrise backend mapping; same-model + dual-implementation cross-check) that blocks delivery, but neither is an owner-decision + blocker anymore. See "Open questions". - Date: 2026-07-29 - Scope: adds the fourth first-class system `vedic` as a plan. This ADR freezes definitions, boundaries and the PR roadmap **before** any contracts or calculation code changes. Companion @@ -151,7 +153,8 @@ engine, not an almanac); only Vaara additionally needs the sunrise day-boundary. - **Vaara** (weekday): runs **from local sunrise to the next local sunrise**, not midnight — a birth before sunrise belongs to the previous weekday. Sunrise definition is itself disputed (documented, e.g., in Drik Panchang's settings: "Edges" = top edge at horizon vs "Middle - Limb" = disc center). **Rule target (proposed): upper-limb sunrise.** Evidence for the + Limb" = disc center). **Owner-confirmed (2026-07-31): upper-limb sunrise with standard 34′ + refraction — model name `upper-limb-standard-refraction`.** Evidence for the installed backend, astronomy-engine 2.1.19 (`astronomy.js`, `SearchRiseSet` doc block + `BodyRadiusAu`): rise is "the moment that the top of the Sun first appears to peek above the horizon", the body's apparent angular radius is applied, and a fixed **34′** atmospheric @@ -159,7 +162,8 @@ engine, not an almanac); only Vaara additionally needs the sunrise day-boundary. numeric mapping to the classical "Sun center at −50′" convention (34′ + fixed 16′ semi-diameter vs astronomy-engine's true apparent radius) is **not yet verified and is a P2/P3 implementation blocker**: it must be pinned by sunrise spot-check goldens before any Vaara - output ships. Disc-center-without-refraction is a recorded alternative for a future ruleset, + output ships or is claimed correct — this is now a verification gate, not an owner-decision + gate. Disc-center-without-refraction is a recorded alternative for a future ruleset, not a v1 option. Elevation is ignored for sunrise in v1 (sea-level horizon), recorded as a caveat. @@ -185,18 +189,17 @@ engine, not an almanac); only Vaara additionally needs the sunrise day-boundary. - **Balance at birth**: `balance = (1 − elapsedFractionOfNakshatra) × lordYears`, where `elapsedFraction = offsetInNakshatra / 13°20′` from the Moon's sidereal longitude at the birth instant. Pure longitude ratio — no day-rounding. -- **Year length model**: **disputed among schools (365.25-day "solar" year vs 360-day savana - year vs sidereal year)** — the models drift apart materially over a life span (a 120-year +- **Year length model**: disputed among schools (365.25-day "solar" year vs 360-day savana + year vs sidereal year) — the models drift apart materially over a life span (a 120-year cycle is ~630 days shorter under savana-360 than under julian-365.25; a sidereal year is - ~365.2564 days, another ~46 days over 120 years). **Candidate: `julian-365.25`** (dasha year = - 365.25 × 86400 SI seconds), the software-mainstream convention — but this is **NOT frozen in - P0**. The P3 dasha implementation is **BLOCKED** on (a) an explicit owner decision and (b) a - same-model cross-check against a second independent implementation (jyotishganit candidate) - configured to the identical year model. P1 may reserve a versioned enum - (`dashaYear: 'julian-365.25' | 'savana-360' | 'sidereal'`) in settings, but **no value may be - wired as the product default** until the owner decision lands; the chosen model is then - recorded in the ruleset/provenance so alternates can ship later as new ruleset versions - without ambiguity. + ~365.2564 days, another ~46 days over 120 years). **Owner-confirmed default (2026-07-31): + `julian-365.25`** — dasha year = 365.25 × 86400 SI seconds; ruleset/provenance ultimately + records `dashaYear: 'julian-365.25'`. `savana-360` and `sidereal` remain reserved enum values + shipping only as future new ruleset versions, never as silent alternates. **The single + remaining Vimshottari blocker is verification, not decision**: the P3 dasha implementation + cannot ship until it passes a cross-check against a second independent implementation + configured to the identical `julian-365.25` model (same-model comparison mandatory; no + majority vote). - **Antar dashas**: within a Maha of lord L, sub-periods follow the same 9-lord sequence starting from L itself; `antarLength = mahaLength × antarLordYears / 120`. - **Endpoints**: every period is a half-open instant interval `[start, end)`; `end` of one @@ -277,8 +280,9 @@ decision (§Open questions); the engine capability does not depend on it. - **P1 — contracts + provider skeleton**: `VedicSettings`, `VedicChartResult` schema, enum extensions above, `packages/vedic` returning `SYSTEM_NOT_YET_IMPLEMENTED`-style honest - pending warnings; no numbers computed. Contract version bumps prepared. May reserve the - versioned `dashaYear` enum, but wires **no product default** for it (§11). + pending warnings; no numbers computed. Contract version bumps prepared. The versioned + `dashaYear` enum was reserved with no default wired; wiring the owner-confirmed + `julian-365.25` default (§11) is P3 work, gated on its cross-check. - **P2 — precise ayanamsha, nine grahas, nodes, Lagna + Swiss golden**: Lahiri (§4) implementation; Sun..Saturn sidereal positions; mean+true Rahu, Ketu opposition; sidereal Lagna. Golden: ≥50 synthetic cases (multi-decade 1900–2100, N/S latitudes, multiple @@ -326,9 +330,10 @@ Until a future independent source passes a field, user-facing and release docume “Swiss-only external numeric reference” for that field and must not claim two-source validation. - **P3 — classifications**: Rashi/Bhava/Nakshatra/Pada/Panchanga/D1/D9/Vimshottari per §§7–12, - including boundary-case unit tests on both sides of every segment edge. **Blocked until** the - Vimshottari year-model owner decision + same-model dual-implementation cross-check (§11) and - the sunrise mapping verification (§9) are done. + including boundary-case unit tests on both sides of every segment edge. Both owner decisions + are done (2026-07-31); what still gates delivery is evidence: Vimshottari cannot ship until + the same-model (`julian-365.25`) dual-implementation cross-check (§11) passes, and Vaara + cannot ship until the sunrise mapping verification (§9) passes. - **P4 — facts & answer layer**: `vedic-rules` sourced findings, InterpretationFacts wiring, AnswerPlan/PublicResult v2, validate-answer update, warning codes + public-copy table, timeAccuracy gating (§13). @@ -351,11 +356,14 @@ Until a future independent source passes a field, user-facing and release docume 1. **Proposed** default `nodes: 'mean'` (vs `'true'`) for `vedic-parashara-lahiri@0.1.0` — awaiting confirmation. -2. **BLOCKED / owner decision**: Vimshottari year model. Candidate: `julian-365.25`; the P3 - dasha implementation is blocked on this decision plus a same-model dual-implementation - cross-check (§11). No default may be wired before then. -3. **Proposed** sunrise rule target "upper-limb" for Vaara — awaiting confirmation; the - backend parameter mapping additionally requires P2 verification evidence (§9). +2. **Resolved 2026-07-31**: Vimshottari year model — owner confirmed `julian-365.25` + (dasha year = 365.25 × 86400 SI seconds; `savana-360`/`sidereal` future-ruleset-only). + Remaining gate is verification only: the same-model dual-implementation cross-check (§11) + must pass before the P3 dasha implementation ships. +3. **Resolved 2026-07-31**: Vaara sunrise rule — owner confirmed upper-limb + standard 34′ + refraction (`upper-limb-standard-refraction`). Remaining gate is verification only: the + backend −50′-mapping must be pinned by P2 sunrise spot-check goldens (§9) before any Vaara + output ships. 4. Should v0.3.0 flip the default `systems` array to all four, or keep 3 and make `vedic` opt-in initially? 5. Public-contract v2 rollout: hard cut in v0.3.0 (recommended) vs dual-emit v1+v2. @@ -367,9 +375,14 @@ Until a future independent source passes a field, user-facing and release docume - The **engineering boundaries** (system id, package split, frame/time-scale choices, Lahiri variant identification, Ketu opposition, whole-sign scope, interval/rounding conventions, contract-break plan, license boundary, golden methodology) are frozen: implementation PRs may - not silently deviate — a deviation requires editing this ADR first. The **semantic defaults** - flagged as proposed/blocked (node default, sunrise mapping, dasha year model) must not be - treated as decided until the owner confirms. + not silently deviate — a deviation requires editing this ADR first. Two categories must not + be conflated: the **frozen owner defaults** (`dashaYear: 'julian-365.25'`; sunrise + `upper-limb-standard-refraction` — both confirmed 2026-07-31) are decided and no longer + reopenable without a new owner decision, while the **verification gates** (same-model + dual-implementation cross-check for Vimshottari; sunrise backend-mapping goldens for Vaara; + the P2 ≤1′ Swiss golden for grahas/nodes/Lagna) still block delivery until their evidence + actually exists. The one remaining **undecided** semantic default is the Rahu node model + (§5), which must not be treated as decided until the owner confirms. - The engine keeps its golden rules: the model never computes charts; missing values are reported, never backfilled; Vedic capability must not be claimed anywhere user-facing until P5 ships (guarded by `tools/vedic-docs.test.ts`). No precision (≤1′ or otherwise) may be claimed diff --git a/tools/vedic-docs.test.ts b/tools/vedic-docs.test.ts index 7f2c168..5aef227 100644 --- a/tools/vedic-docs.test.ts +++ b/tools/vedic-docs.test.ts @@ -44,16 +44,25 @@ describe('vedic docs gate: P0 deliverables present and complete', () => { expect(adr).toMatch(/never be\s+treated as\s+synonyms/i); }); - it('ADR 0013 keeps semantic defaults as proposed/blocked, not silently accepted', () => { + it('ADR 0013 keeps owner-confirmed defaults and verification gates distinct', () => { const adr = read(ADR); - // Status must stay Proposed until the owner confirms the semantic defaults. + // Status must stay Proposed while the Rahu node default awaits owner confirmation. expect(adr).toMatch(/- Status: Proposed/); expect(adr).not.toMatch(/- Status: Accepted/); - // The Vimshottari year model is an explicit blocker, never a wired default. - expect(adr).toMatch(/BLOCKED \/ owner decision.*Vimshottari year model/is); - expect(adr).not.toMatch(/default is the \*\*365\.25-day/i); - // Sunrise backend mapping stays an unverified P2/P3 blocker until evidence lands. + // julian-365.25 is the owner-confirmed default (2026-07-31), not a pending candidate. + expect(adr).toMatch(/Owner-confirmed default \(2026-07-31\):\s+`julian-365\.25`/i); + expect(adr).not.toMatch(/BLOCKED \/ owner decision.*Vimshottari year model/is); + // The only remaining Vimshottari gate is the same-model dual-implementation cross-check. + expect(adr).toMatch( + /remaining Vimshottari blocker is verification[\s\S]*?identical `julian-365\.25` model/i, + ); + // Sunrise rule is owner-confirmed upper-limb + standard 34′ refraction. + expect(adr).toMatch(/Owner-confirmed \(2026-07-31\): upper-limb sunrise with standard 34′/); + expect(adr).toContain('upper-limb-standard-refraction'); + // The −50′ backend mapping stays an unverified P2/P3 blocker until goldens land. expect(adr).toMatch(/not yet verified and is a P2\/P3\s+implementation blocker/i); + // Rahu remains the single undecided semantic default. + expect(adr).toMatch(/\*\*Proposed\*\* default `nodes: 'mean'`/); }); it('keeps the P2 evidence amendment field-scoped without lowering the Swiss gate', () => {