Commit Graph
886 Commits
Author SHA1 Message Date
ClaudeandClaude Opus 5.5 97afd1716a feat: chart choice replaces event-scored rectification page
Event scoring was measured at chance level on the 77 Rodden-AA holdout
cases (BUG-1091). The new flow finds the dividing line nearest the reported
time, describes how the flipped divisional charts read on either side, asks
up to five self-assessment questions, and saves the user's own choice
(provenance user_choice) with the domains to read in both versions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXozbkyFNqbu8pVEtZ7W
2026-11-06 02:06:17 +08:00
ClaudeandClaude Opus 5.5 e2c61f1a9a fix(consult): carry the next dasha periods on the card for long-range questions (BUG-1643)
A ten-year career question got a timing section that stopped at the running
Vimshottari mahadasha and the running Narayana sign, so the answer padded the
decade with "no period available" sentences and could not compare the systems.

- API: dasha_sub_periods.next_mahadasha (next MD cut by the same
  dasha_analyzer.build_antardasha); frozen engine files untouched.
- Card: every card carries the next MD and next Narayana sign; a question
  that looks N years ahead also gets timing.horizon, the next MD's
  antardashas, later MDs inside the horizon and two to four Narayana signs
  with years, all copied from the engine.
- Goldens: only the new engine field grafted in (rest byte-identical).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-05 23:59:05 +08:00
ClaudeandClaude Opus 5.5 2d65773c06 fix(annual): no 顺/紧 verdicts, wording slips no longer stop a report, a waiting card shows the step (BUG-1640)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXozbkyFNqbu8pVEtZ7W
2026-11-05 22:07:01 +08:00
ClaudeandClaude Opus 5.5 f4f38f1a54 fix(annual): no more 有顺有紧; windows and 年尾 get the program's lean (BUG-1635)
Lean v2 is a weighted sum (AD 2, Narayana AD 2, PD 1; a tie follows the
Vimshottari AD) with only 偏顺 / 偏紧 / 平稳. Phases with both sides keep a
counterweight limit. Window, domain-window, year-end and remember evidence
carry the lean; the gate rejects mixed wording and a window lean that
contradicts the program.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXozbkyFNqbu8pVEtZ7W
2026-11-05 17:45:38 +08:00
ClaudeandClaude Opus 5.5 7827d9aff0 chore(rectification): re-freeze after the BUG-1622..1626 renumber (ERR-110)
The renumber (093da446) changed comments in shadbala.py and both replay
scripts, so the frozen identity moved. On top of staging 849343cd:
FREEZE / REPORT constants first, --freeze, then replay:
astrologer_166d_2026_11_05; contract rotated with previous =
astrologer_166c_2026_11_05 (kept byte-for-byte).

Versus astrologer_166c_2026_11_05 and astrologer_166b_2026_11_04: sealed 20
and reported offset 900 all identical, metrics and summary identical,
historical changed_trial_count 10 / 731. Still scoring-15; no tuning.
BUG-1622 records the second re-freeze.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-05 15:35:31 +08:00
ClaudeandClaude Opus 5.5 093da4468d docs: renumber this branch's records BUG-1613..1617 -> BUG-1622..1626
Another session shipped a different BUG-1613 (loading curtain) to staging.
Mapping in order: 1613->1622, 1614->1623, 1615->1624, 1616->1625,
1617->1626, in BUG_HISTORY headings and bodies, CHANGELOG, ledger, research
notes, code comments, rule text, test notes and the holdout contract text.
Text only. shadbala.py and the two replay scripts are in the frozen identity,
so an ERR-110 re-freeze follows in the next commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-05 15:32:05 +08:00
ClaudeandClaude Opus 5.5 7174fda7a9 refactor(arudha): move the PVR dual-lord selector into scripts/arudha_reference/ (BUG-1617)
The quick gate's tests/test_python_hygiene_budget.py caps root scripts at 441
("locally written files must not increase"); the new module made it 442.
Moved to the subpackage scripts/arudha_reference/pvr_dual_lord.py; CLI
import tries both import styles; tests, BUG-1617 and the status table updated.
No frozen file touched; behaviour unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-05 15:31:51 +08:00
ClaudeandClaude Opus 5.5 3c81ebf3cf chore(rectification): re-freeze sealed holdout and offset sweep for the #166 2026-11-05 labels (ERR-110, BUG-1613..1617)
shadbala.py (frozen identity) changed in 5ffef30a: labels, comments and the
shared mercury_malefic_companions() helper, no value change. Scoring identity
stays rectification-v5-matrix-scoring-15; no ALGORITHM_VERSION bump.

FREEZE / REPORT constants first, --freeze, then replay (after all code
commits of this branch, 09fd3a42): astrologer_166c_2026_11_05; contract
rotated with previous = astrologer_166b_2026_11_04 (kept byte-for-byte).

Versus astrologer_166b_2026_11_04, trial by trial:
- sealed 20: all identical; metrics identical (top-1 0.40, top-3 0.45, mean
  minute error 6.95); historical changed_trial_count still 10.
- reported offset 900: all identical; summary identical (top-1 hits at
  +-15/30/60 4/3/0, top-3 31/34/30, delivery coverage at +-15 219, mean top-1
  minute error 20.52); historical changed_trial_count still 731.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-05 15:31:43 +08:00
ClaudeandClaude Opus 5.5 008201aec1 feat(arudha): opt-in PVR §15.5.1 dual-lord selector for Scorpio / Aquarius Arudha (BUG-1617)
Astrologer 2026-11-05 (#166 comment 39249, item 3; Q28). New module
scripts/arudha_lord_selection_pvr.py, reference only, labelled
"PVR 双宫主比较(参考,未进默认)".

- select_pvr_arudha_lord(): PVR Vedic Astrology: An Integrated Approach
  §15.5.1 (print pp. 201-203, PDF 213-215), first deciding level wins:
  1 only one lord in the sign -> the other; 2 companions (nine grahas, the
  Lagna excluded, nodes counted); 3 Jupiter / Mercury / dispositor support by
  conjunction or rasi drishti, a planet in two roles counted twice; 4 exalted;
  5 dual > fixed > movable; 6 degree, nodes as 30 - deg. Returns winner or
  blocked (full tie, dual-lord dispositor loop, missing longitude), both
  candidates, the deciding level and a trace; engineering choices listed.
- pvr_arudha_reference(): default fixed-lord pada next to the PVR pada for
  the houses on Scorpio / Aquarius, using jaimini.calc_arudha_pada_for_house
  (the one pada implementation) with the chosen lord's longitude.
- CLI `jaimini` (mode all / arudha) gains arudha_dual_lord_pvr_reference.
  Default A1-A12 / AL / UL, the chart page, the consultation card and
  rectification scoring do not use it; jaimini.py and the Chara co-lord
  selector are untouched (byte check against the frozen identity in tests).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-05 15:31:43 +08:00
ClaudeandClaude Opus 5.5 6e10c7242e docs(moolatrikona): label the in-varga D9 Moolatrikona as pending; correct the V.P. Jain provenance (BUG-1613)
Astrologer 2026-11-05 (#166 comment 39249, item 1). No calculation change.

- jyotish_engine.VARGA_MOOLATRIKONA_BASIS = in_varga_degree_band_pending_review:
  a D9 Moolatrikona is decided by the in-varga degree inside the D1 band;
  whether / how Moolatrikona applies in vargas is pending. Written on each
  d9_navamsa_expanded row (moolatrikona_basis) and on the consultation D9
  summary (not copied to the evidence card).
- "V.P. Jain example" corrected to "PyJHora test transcription"
  (pvr_tests.py::shadbala_VPJainBook_tests, no edition or page) in the data
  audit notes and the competitive analysis (ERR-081 recurrence).
- astrologer_questions.md: status table of the seven 2026-11-05 items.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-05 15:31:43 +08:00
ClaudeandClaude Opus 5.5 1c298c7257 fix(yoga): strict Gajakesari no longer counts a natural-malefic Mercury as a supporter (BUG-1615)
Astrologer 2026-11-05 (#166 comment 39249, item 6): PVR §11.6 strict
definition needs a benefic supporter; a Mercury that is malefic by
association must follow the chosen natural-nature rule.

- New sandbox helper mercury_malefic_companions() calls
  shadbala.mercury_malefic_companions (the one implementation of
  MERCURY_NATURE_CONVENTION: same sign as Sun / Mars / Saturn / waning Moon,
  nodes excluded), imported lazily; no import cycle.
- gajakesari: Mercury is dropped from benefic_links when malefic; when Venus
  still supports, a trigger names the excluded Mercury.
- gajakesari_strong_jupiter_variant: its "strict does not hold" check uses the
  same rule, so the two rules stay mutually exclusive; the variant itself uses
  no supporter.
- Labels: natural (not five-fold) enmity for the enemy-sign test and the Moon
  excluded as a supporter are both pending astrologer review.

yoga_engine.py / yoga_rules.json are not in the frozen identity.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-05 15:31:43 +08:00
ClaudeandClaude Opus 5.5 8eeac79ad2 feat(shadbala): label provisional / pending #166 conventions, share the Mercury rule (BUG-1613, BUG-1614)
Astrologer reply 2026-11-05 (#166 comment 39249). Labels, comments and one
shared helper; no value changes.

- method_variants.saptavargaja_moolatrikona = d1_degree_band_only_provisional:
  BPHS 27.2-4 (Santhanam p. 265) confirms 45 and extends it to the other six
  vargas; "D1 only, degree band" is a provisional implementation, not BPHS.
  The "V.P. Jain example" is a PyJHora test transcription (ERR-081).
- method_variants.drik_mercury_jupiter = quarter_only_raman_pending, with the
  1x / Santhanam-literal 1.25x / Raman 1/4 readings documented; no additive
  variant added.
- MERCURY_NATURE_CONVENTION renamed to say the node exclusion is an
  implementation choice (the base text lists Rahu / Ketu as malefics) and the
  waning Moon is included; the p. 28 translator's note is not adopted.
  mercury_malefic_companions() is now the one implementation of the rule
  (classify_drik_planets calls it; the yoga engine will too).
- 26.11-12 special aspects: citation Santhanam p. 256 added; endpoint tests at
  +/- 0.01 around 150 / 210 / 270 and the round(angle, 2) snap.

shadbala.py is in the frozen identity: ERR-110 re-freeze follows in a separate
commit after the remaining code changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-05 15:31:43 +08:00
ClaudeandClaude Opus 5.5 3e7388c37f feat(narayana): default to Sanjay Rath, keep the legacy algorithm as a labelled comparison (BUG-1601, #166 Q9)
Product decision 2026-11-04 on astrologer ruling #166 Q9. One builder,
narayana_legacy_label.product_narayana, makes the product Narayana object:
the Rath view on top (label "Sanjay Rath 版(默认;…)", seed sign, 24 MDs,
running MD / AD with remaining_years, the running MD's ADs) and the whole
labelled legacy result under `legacy`. When Rath cannot decide a start sign
the object says blocked in plain words; legacy never stands in.

- Consultation card: timing.narayana is Rath; the legacy running MD rides
  as a short timing.narayana_legacy; timing.narayana_rath is gone.
- Full reading / report: Rath block first, "- 对照:旧算法…" after; the
  parity chapter lists Rath (default), source-aware and legacy (comparison);
  dasha master pack Narayana periods are the Rath MDs.
- /api/dasha narayana: periods are Rath, legacy under `legacy`.
- Annual: Rath is the product timeline (used_by_product_timeline true),
  narayana_skeleton_profile "rath", legacy is the reference and never counts.
- CLI narayana-dasha prints Rath first, legacy as comparison.
- Consult full-data cache schema v2 -> v3 so old legacy-default packets miss.

Rectification scoring is untouched and still calls calc_narayana_mahadasha
(frozen identity). Evidence-card, biography and card-facts captures were
regenerated with their scripts; annual-report-facts.json was regenerated from
its endpoint function. Tests pinning legacy-as-default are rewritten with
原值/新值/原因.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-05 04:32:07 +08:00
ClaudeandClaude Opus 5.5 013f889529 chore(rectification): re-freeze sealed holdout and offset sweep for #166 batch 2 at scoring-15 (ERR-110, BUG-1590..1598)
Independent Staging Quality Gate / validate-frontend (push) Successful in 6m25s
Independent Staging Quality Gate / validate-python (push) Successful in 6m30s
Independent Staging Quality Gate / publish (push) Successful in 3m3s
FREEZE / REPORT constants first, --freeze, then replay:
astrologer_166b_2026_11_04 (frozen after 7ff447ac); contract rotated with
previous = astrologer_166_2026_11_04 (kept byte-for-byte).

Versus astrologer_166_2026_11_04 (no tuning):
- sealed 20: all identical, metrics unchanged.
- reported offset 900: 114 changed; top-1 hits at +-15/30/60 stay 4/3/0;
  top-3 30/34/29 -> 31/34/30; delivery coverage at +-15 220 -> 219; mean
  top-1 minute error 20.87 -> 20.52.

BUG-1590..1598 recorded; ledger and CHANGELOG lines added.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-04 22:42:41 +08:00
ClaudeandClaude Opus 5.5 7ff447ac67 fix(engine): keep the Chinese report free of English glue from #166 triggers and cell notes (BUG-1596, BUG-1597, BUG-1590)
Quick gate: test_report_english_sweep_smoke counted 3 zh_han_function_glue
hits on chart #1, all new in 4b223eb8: the Matrunasa 199 trigger "Moon ->
Mercury -> Moon in house 8" (the renderer turns "house" into Chinese and
leaves "in") and the English ambiguous_cell_notes ("Lagna lord, ...").

- A custom rule's trigger item may be a (Chinese, English) pair; the Chinese
  combination uses the Chinese items, combination_en and `triggers` the
  English ones, `triggers_zh` the Chinese. Gajakesari, the variant and both
  Matrunasa rules emit pairs (PLANET_ZH in the sandbox).
- ambiguous_cell_notes carry Chinese summary / basis plus summary_en /
  basis_en, worded without the glue words.
No role or score changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-04 22:39:15 +08:00
ClaudeandClaude Opus 5.5 f61d279aec fix(rectification): bump scoring identity to scoring-15 for #166 batch 2 (BUG-1590)
4b223eb8 makes Gemini Saturn (8, 9) and Virgo Saturn (5, 6) functionally
mixed; the *_functional_* rules read the functional layer, so the same input
scores differently for those ascendants. Per BUG-1181:
rectification-v5-matrix-scoring-14 -> -15. Policy v4, input contract v5 and
the dated window contract unchanged; the SQL guard already accepts it.

- Memoization golden v8 (source_commit 4b223eb8); v7 pinned by sha256. This
  public request's candidate scores are unchanged.
- scoring-15 cross-midnight golden (independent-process A/B 3 x 7 equal);
  scoring-14 golden kept as history and opens read-only with recompare.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-04 22:29:06 +08:00
ClaudeandClaude Opus 5.5 4b223eb8ea fix(engine): apply #166 batch 2 rulings to functional roles, yogas, Chara / Narayana, Gulika, sunrise records and varga methods (BUG-1590..1598)
Astrologer ruling 2026-11-04 on #166, product decisions the same day (Q9
display only, later; Q12 record, do not switch).

- Q4 (BUG-1590): Gemini Saturn (8, 9) and Virgo Saturn (5, 6) are mixed
  (neutral), not pure benefics by trine priority; the astrologer's table for
  the eight ambiguous cells rides along as ambiguous_cell_notes. Other
  lordships are kept.
- Q10 (BUG-1591): Chara Dasha with both Scorpio / Aquarius lords in the sign
  is fixed at 12 years (Ketu exalted in Scorpio gave 13).
- Q11 (BUG-1592): legacy Narayana counts only the nine grahas as occupants.
- Q8 (BUG-1593): Narayana period reports the adjustment that took effect
  (Mercury in Virgo: 12, +0, not "12 + 1" capped silently).
- Q15 (BUG-1594): upagrahas carry both raw Saturn-part points and name the
  mapping (PyJHora-compatible Gulika = start, Maandi = midpoint; PVR 4.3 is the
  reverse and is listed, never claimed).
- Q12 / Q13 (BUG-1595): every day/night window, Shadbala and the birth
  Panchanga record their sunrise convention and hora method. No value changes.
- Q5 (BUG-1596): "Gajakesari Yoga" is PVR's strict definition (benefic
  association, not debilitated, combust or in a natural enemy's sign); the
  strong-Jupiter variant and the bare Moon-Jupiter kendra relation are
  separate rules outside the card's closed list. New sandbox helpers combust()
  and in_natural_enemy_sign().
- Q6 (BUG-1597): Matrunasa split into Raman 198 (named Parashari aspects,
  nodes for conjunction / hemming only) and Raman 199 (same parents-card row
  via canonical_mapping); each hit names its trigger; "high confidence" and
  mother's-health effects removed. Custom rules may set `triggers`.
- Q31 (BUG-1598): calc_varga names the D3 / D24 / D30 / D60 method; D3 / D24 /
  D60 of varga.py and divisional_charts_extended agree on every 0.1 deg.
- Q29: the 7-karaka note says PiK does not apply in that scheme.

tests/test_astrologer_rulings_166_batch2.py (25 tests). Rectification
identity and re-freeze follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-04 22:24:40 +08:00
ClaudeandClaude Opus 5.5 1989649f70 chore(rectification): re-freeze sealed holdout and offset sweep for the #166 rulings at scoring-14 (ERR-110, BUG-1581..1589)
FREEZE / REPORT constants first, --freeze, then replay: astrologer_166_2026_11_04.
Contract rotated with previous = d30_venus_2026_11_04 (kept byte-for-byte);
freshness test and frontend confirmation-gate test updated.

Versus d30_venus_2026_11_04 (no tuning):
- sealed 20: 17 identical / 3 changed (case 6 true_rank 8 -> 4, case 16
  13 -> 11, case 20 1 -> 8 with minute error 10 -> 8); top_1 0.45 -> 0.40,
  top_3 0.50 -> 0.45, MAE 7.05 -> 6.95, coverage 0 unchanged.
- reported offset 900: 584 identical / 316 changed (rank better 122, worse
  139); top-1 hits at +-15/30/60 4/3/0 and top-3 30/34/29 unchanged; delivery
  coverage at +-15 219 -> 220; mean top-1 minute error 19.51 -> 20.87.
No per-ruling attribution replay was run.

BUG-1581..1589 recorded (BUG-1575 resolved with BUG-1583); ledger and
CHANGELOG lines added.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-04 21:14:16 +08:00
ClaudeandClaude Opus 5.5 1ce4eec53c fix(rectification): bump scoring identity to scoring-14 for the #166 rulings (BUG-1583..1588)
78f98eba changes the same-input rectification scores: Shadbala Sthana and Drik
feed the Shadbala auxiliary (BPHS Saptavargaja values, Moolatrikona 3 / 15 deg,
whole-sign Kendradi, BPHS 26 special aspects, Mercury with any malefic) and
jaimini.calc_arudha_padas feeds the event engine and feature facts. Per
BUG-1181 the algorithm identity moves rectification-v5-matrix-scoring-13 ->
-14. Policy v4, input contract v5 and the dated window contract (generation
>= 9) are unchanged; the SQL guard accepts scoring-(9|[1-9][0-9]+), so no
migration.

- Memoization golden v7 written by write_golden (source_commit 78f98eba); v6
  stays byte-identical and is pinned by sha256. For this public request the
  candidate scores are unchanged (12:00 8.5336, 12:01 8.5242, 12:02 8.088);
  the Shadbala fingerprints, feature hash and candidate UUID moved.
- New scoring-14 cross-midnight golden from midnight_date_anchor_regression.py
  --golden (baseline = this tree; independent-process A/B 3 x 7 fields equal);
  scoring-13 golden kept as history and opens read-only with recompare.
- Dated-transitions scan unchanged (test passes without regeneration).
- v9EngineVersion() default and the identity tests follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-04 21:10:43 +08:00
ClaudeandClaude Opus 5.5 78f98eba93 fix(engine): apply the #166 astrologer rulings to Shadbala, Arudha and D30 (BUG-1581..1589, BUG-1575)
Astrologer ruling 2026-11-04 on #166; product decision the same day (Moon
option C, rulings implemented as given). The default is a named BPHS version;
the pre-#166 precise Sthana / Drik is kept byte-for-byte as variant
"raman_gbb" (Raman, Graha and Bhava Balas Ex. 13 / 55 still pass on it).

- Q3 (BUG-1581): the Moon's own Paksha is P on both sides (Sanskrit 27.11 lists
  indu), Chesta = Paksha, total 2P. Drik still classifies a waning Moon as a
  malefic (Q26), classify_drik_planets unchanged for the Moon.
- Q2 (BUG-1582): the Sun's Ayana is not doubled; Chesta = base Ayana; A + A.
  On the VP Jain fixture Kala + Chesta = 46.73 + 35.07 = published 81.80 + 0.
- Q18 (BUG-1583, BUG-1575): Moolatrikona Moon Taurus from 3 deg, Mercury Virgo
  from 15 deg, in shadbala.py and jyotish_engine.MOOLATRIKONA.
- Q16 / Q20 (BUG-1584): Saptavargaja 45/30/20/15/10/4/2, compound relation from D1.
- Q25 (BUG-1585): Mercury is a natural malefic with any natural malefic in its
  sign (nodes not counted, recorded as an implementation choice).
- Q24 (BUG-1586): BPHS 26.9-12 piecewise special aspects replace the general
  segment for Saturn, Mars and Jupiter; a single aspect stays within 0-60.
- Q21 (BUG-1587): Kendradi Bala by whole sign from the Lagna sign.
- Q27 (BUG-1588): jaimini.calc_arudha_pada_for_house takes the 10th from the
  first-count pada (pada in the 7th -> 4th from the house), as special_lagnas did.
- Q30 (BUG-1589): D30 degree inside the sign is proportional within the
  unequal span in varga.py; divisional_charts_extended uses exact 30/7.
- method_variants names every convention. Q22 edges and the Q24 60 cap are
  locked in tests/test_astrologer_rulings_166.py (42 tests).

Raman / PyJHora comparison tests now run on "raman_gbb"; the VP Jain report
labels the new convention rows; chart-insight-golden.json's planets-only
Shadbala section regenerated from /api/shadbala. Rectification identity,
golden and re-freeze follow in separate commits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-04 21:08:32 +08:00
ClaudeandClaude Opus 5.5 71d38b0d67 chore(rectification): re-freeze sealed holdout and offset sweep for D30 and Venus roles at scoring-13 (ERR-110, BUG-1560, BUG-1570)
Independent Staging Quality Gate / validate-python (push) Successful in 7m24s
Independent Staging Quality Gate / validate-frontend (push) Successful in 7m25s
Independent Staging Quality Gate / publish (push) Successful in 2m59s
FREEZE / REPORT constants first, --freeze, then replay: d30_venus_2026_11_04.
Contract rotated with previous = audit_wave2_2026_11_04 (kept byte-for-byte);
freshness test and frontend confirmation-gate test updated.

Versus audit_wave2_2026_11_04 (product accepted these costs 2026-11-04, no
tuning):
- sealed 20: 17 identical / 3 changed (case 5 rank 1 -> 3, case 18 12 -> 10,
  case 14 reasons only); top_1 0.50 -> 0.45, MAE 6.65 -> 7.05; top_3 0.50 and
  coverage 0 unchanged. All from the D30 table.
- reported offset 900: 650 identical / 250 changed; top-1 hits at
  +-15/30/60 14/17/15 -> 4/3/0 of 300 (all from Venus roles); top-3 and
  delivery coverage unchanged at every radius; mean minute error
  19.79 -> 19.51 (from D30).
Attribution from single-fix replays on git-archive copies: D30 alone 3 sealed
/ 166 offset trials, Venus alone 0 / 108; they overlap only in case 20.

BUG-1560 and BUG-1570 resolved; ledger and CHANGELOG lines added.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 17:46:58 +08:00
ClaudeandClaude Opus 5.5 9fd3fcd5ba fix(rectification): bump scoring identity to scoring-13 for BPHS D30 and Venus roles (BUG-1560, BUG-1570)
18c685c4 changes the same-input rectification scores (varga.py even-sign D30
feeds health_pressure and feature facts v4; functional roles feed the
*_functional_*_auxiliary rules), so per BUG-1181 the algorithm identity moves
rectification-v5-matrix-scoring-12 -> -13. Policy v4, input contract v5 and
the dated window contract (generation >= 9) are unchanged; the SQL guard
already accepts scoring-13, so no migration.

- Memoization golden v6 written by write_golden (source_commit 18c685c4);
  v5 stays byte-identical and is pinned by sha256. For this public request
  the candidate scores are unchanged; the D30 feature (Capricorn -> Pisces),
  its transition row and the feature hashes moved.
- frontend/tests/fixtures/rectification-dated-transitions.native.json: scan
  regenerated from the real engine (D30 segment start Capricorn -> Pisces),
  CRLF kept.
- New scoring-13 cross-midnight golden from midnight_date_anchor_regression.py
  --golden (independent-process A/B 3 x 7 fields equal); scoring-12 golden kept
  as history and opens read-only with recompare under scoring-13.
- v9EngineVersion() default and the identity tests follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 17:36:13 +08:00
ClaudeandClaude Opus 5.5 18c685c428 fix(engine): even-sign D30 per BPHS ch. 6 and Venus malefic for Aries / Scorpio per BPHS 34 (BUG-1560, BUG-1570)
Product decision 2026-11-04: the calculation follows the sources even though
rectification scores move.

- scripts/varga.py: even-sign Trimsamsa 12-20 Pisces, 20-25 Capricorn,
  25-30 Scorpio (was Capricorn / Scorpio / Pisces). KNOWN DEFECT comment
  removed; the strict xfail in tests/test_varga_bphs_starts_audit_g.py is now
  an ordinary test and the 0.1-degree BPHS sweep covers varga.py on all signs.
- scripts/functional_benefics.py: ROLE_OVERRIDES adds Venus = malefic for
  Aries (BPHS 34.20) and Scorpio (34.35); profile doc lists both cells.

Both feed rectification scoring; the scoring-13 identity bump, memoization
golden v6 and the ERR-110 re-freeze follow in the next commits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 17:33:26 +08:00
ClaudeandClaude Opus 5.5 607a48b6c3 chore(rectification): re-freeze sealed holdout and offset sweep once for the merged audit wave 2 (ERR-110)
Independent Staging Quality Gate / validate-frontend (push) Successful in 6m27s
Independent Staging Quality Gate / validate-python (push) Successful in 6m34s
Independent Staging Quality Gate / publish (push) Successful in 3m1s
G (BUG-1560/1561: varga.py, divisional_charts_extended.py), H (BUG-1566/1567:
jaimini.py) and J (BUG-1270/1576: shadbala.py) each changed frozen identity
files and each froze its own audit_g / audit_h / audit_j record, which only
matches that branch's tree. Per ERR-110 the merged tree is frozen once as
audit_wave2_2026_11_04 (FREEZE/REPORT constants first, --freeze, then replay).
The contract now points at audit_wave2 with moon_paksha_2026_11_04 as the
previous record; the per-branch records are kept byte-for-byte and named as
intermediate in the superseded_reason notes. Freshness test and frontend gate
test updated.

Compared field by field with moon_paksha_2026_11_04: sealed holdout 20/20
trials identical, metrics unchanged; reported offset 900/900 identical,
summary unchanged; changed_trial_count vs 2026-09-20 stays 8 / 581.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 17:24:31 +08:00
ClaudeandClaude Opus 5.5 1cdd9c827c merge: data audit wave 2 J (Dig Bala arc fold BUG-1270, deterministic Drik BUG-1576, BUG-1575 logged)
Freeze contract, FREEZE/REPORT constants and gate tests keep the G state
here; the merged tree is re-frozen once as audit_wave2_2026_11_04 next.
J's audit_j records are kept byte-for-byte as history.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 17:05:52 +08:00
ClaudeandClaude Opus 5.5 728b077d44 merge: data audit wave 2 I (yoga rules and Parivartana Raja Yoga, BUG-1570..1573)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 17:05:37 +08:00
ClaudeandClaude Opus 5.5 359504a9df merge: data audit wave 2 H (Chara co-lord/antardasha, gulika night, natal vara, BUG-1565..1569)
Freeze contract, FREEZE/REPORT constants and gate tests keep the G state
here; the merged tree is re-frozen once as audit_wave2_2026_11_04 at the end.
H's audit_h records are kept byte-for-byte as history.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 17:05:15 +08:00
ClaudeandClaude Opus 5.5 895a75a2ed chore(rectification): re-freeze sealed holdout and offset sweep for the varga fixes (ERR-110)
BUG-1560 / BUG-1561 changed scripts/varga.py and
scripts/divisional_charts_extended.py, both in the frozen scoring identity.
Per ERR-110 new records were created with each script's --freeze and
replayed as audit_g_2026_11_04; scripts, contract, freshness test and the
frontend gate test point at them. Prior records are kept byte-for-byte.

Compared field by field with moon_paksha_2026_11_04: sealed holdout 20/20
trials identical, metrics unchanged; reported offset 900/900 identical,
summary unchanged; changed_trial_count vs 2026-09-20 stays 8 / 581.
(The D16/D20/D27/D45 and extended-module charts are not read by scoring.)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 17:02:53 +08:00
ClaudeandClaude Opus 5.5 ba27b0e758 fix(varga): D16/D20/D27/D45 starts and the chart-page D30/D40 follow BPHS ch. 6 (BUG-1560..1562)
Data audit wave 2 (G): 19 fixed charts, Raman and Lahiri, mean nodes, both
engines set explicitly. Against PyJHora method 1 ("traditional Parasara") on
the same longitudes, varga.py matched D16/D20 26%, D27 25%, D45 14%, and
divisional_charts_extended (chart page, consultation varga spectrum) matched
D16/D20 7%, D27 14%, D40/D45 25%, D30 50%. jyotishganit agrees with PyJHora
190/190 on every one of these, and both follow BPHS ch. 6.

- varga.varga_map: D16/D45 movable/fixed/dual from Aries/Leo/Sagittarius,
  D20 from Aries/Sagittarius/Leo, D27 fiery/earthy/airy/watery from
  Aries/Cancer/Libra/Capricorn (were odd/even starts). BUG-1560.
- divisional_charts_extended: D16/D20/D27/D40/D45 signs now read varga_map;
  D30 uses the BPHS signs (odd 25-30 Libra; even Taurus, Virgo, Pisces,
  Capricorn, Scorpio). BUG-1561.
- trimshamsa_d30: even-sign table copied from jyotishganit swapped Jupiter
  and Saturn; now 12-20 Pisces, 20-25 Capricorn, 25-30 Scorpio. BUG-1562.
- shodasavarga guide: D4/D10/D24/D27/D30/D40 rule text corrected.

Held back: varga.py even-sign D30 has the same defect, but it feeds
rectification scoring. Fixing it moved the sealed holdout (top-1 0.50 to
0.45) and 166/900 offset trials and turned the memoization goldens red,
which per BUG-1260/1275 means a scoring-13 identity: a product decision.
It carries a KNOWN DEFECT comment and a strict xfail test.

After: same-longitude agreement with PyJHora is 190/190 for D3-D60 in
divisional_charts_extended and for every varga.py chart except D30.
D9/D10/D12, karakas and Arudha are unchanged; the evidence card check
(27 cards, 765 fields) shows 0 differences before and after.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 17:02:53 +08:00
ClaudeandClaude Opus 5.5 d4cde02e6f fix(shadbala): fold the Dig Bala arc (BUG-1270) and make Drik Bala deterministic (BUG-1576)
Dig Bala took |powerless point - planet| / 3 without folding arcs above
180 degrees, so 35 of 140 values on the 19 benchmark charts plus Steve Jobs
exceeded the 60 Virupa maximum (up to 98.98). BPHS 27.7 ("hitva
shadbhadhike sati"; Santhanam: "If the sum is above 180 degrees, deduct the
sum from 360") and Raman, Graha and Bhava Balas section 44-45, Ex. 14-15
(Kuja arc 167 05, Digbala 55.70) both fold. PyJHora's default _dig_bala has
the same unfolded formula, which is why the comparison always "matched";
its own _dig_bala_another, VedAstro source, jyotishganit and saravali fold.
After the fix all 140 values equal PyJHora _dig_bala_another.

Drik Bala summed the aspecting planets in set order. Each Sphuta value is
already rounded to 0.01, so the quarter often sits on a .xx5 edge and the
result moved by 0.01 with PYTHONHASHSEED. Sum whole hundredths in sorted
order and round the quarter half away from zero; 14 of 140 values move by
0.01. Formulas, tables and benefic/malefic classification are unchanged.

New tests lock Raman's Standard Horoscope Ex. 13 (Sthana), Ex. 15 (Dig)
and Ex. 55 (Drik), the fold bounds, and seed-independent Drik. Updated
expectations: test_shadbala_precise_context (PyJHora default Dig carried
the bug) and the Jobs Moon total in test_shadbala_moon_paksha_convention.

shadbala.py is in the rectification frozen identity, so per ERR-110 both
fixes were frozen and replayed once as audit_j_2026_11_04. Compared field
by field with moon_paksha_2026_11_04: sealed holdout 20/20 and reported
offset 900/900 identical, metrics and summary unchanged.

Also records BUG-1575 (jyotish_engine MOOLATRIKONA gives the Moon Taurus
0-3; investigating, not changed).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 16:57:16 +08:00
ClaudeandClaude Opus 5.5 5f234c315b fix(jyotish): Chara co-lord and antardasha, night time-segment points, pre-sunrise weekday; re-freeze as audit_h (BUG-1565..1568)
Data audit wave 2 (H) against PyJHora 4.8.6 and Swiss Ephemeris, 19 charts,
Raman and Lahiri passed explicitly to both sides.

- BUG-1566 (jaimini.py): the K.N. Rao Chara Scorpio / Aquarius lord read both
  co-lords' dignity in the dasha sign itself, so Scorpio was always Ketu and
  Aquarius always Saturn. Now one lord in the sign gives way to the other
  (K.N. Rao; Rath p.43 (c); PyJHora); otherwise compared where each stands
  (companions, Jupiter / Mercury / dispositor, dignity, modality, degrees).
  MD years vs PyJHora 212/228 -> 225/228 (Raman), 226/228 (Lahiri).
- BUG-1567 (jaimini.py): K.N. Rao antardashas now run each MD's own
  direction with the MD sign last (pp.35-36); book order 19/228 -> 228/228.
- BUG-1565 (gulika.py): Wednesday-Saturday night share table started one lord
  early; Maandi and the four other time-segment points 79/114 -> 114/114
  against an independent Swiss computation. Gulika unchanged (19/19).
- BUG-1568 (jyotish_engine.py): natal Panchanga vara / hora used the civil
  date; a birth before sunrise belongs to the previous weekday (15/19 -> 19/19
  vs PyJHora drik.vaara).

Narayana (legacy and Rath), transits, sunrise and day/night: no defect; the
second-cycle rule matches PyJHora's. Variants are listed in BUG_HISTORY.

jaimini.py is in the frozen identity: per ERR-110, new records frozen and
replayed as audit_h_2026_11_04; contract, freshness test and frontend gate
test rotated. Versus moon_paksha_2026_11_04: sealed 20/20 and reported offset
900/900 identical, metrics and summary unchanged. Chara sections of two
frontend fixtures and the rashi-dasha PyJHora fixture's native rows updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 16:53:31 +08:00
ClaudeandClaude Opus 5.5 5a112bf5f5 fix(yoga): revive nine custom rules and Raja Yoga (Parivartana) (BUG-1571, BUG-1572)
Data audit wave 2 (I). 04d901e1 (2026-06-27) renamed the evaluator's
pyjhora_* helpers to external_benchmark_* but left the rule expressions
calling the old names; the NameError is swallowed, so nine rules (Matru
Sneha on the parents card, Bhratruvriddhi, Amala, Sumukha, Bandhu Pujya,
Kaalanirdesat Puthranaasa, ...) never formed. The rule library now calls
the current names; logic is unchanged. Against PyJHora (Raman, mean nodes,
19 samples) the revived rules agree 18-19/19; the 20 Raman packet rules
go from 302/380 to 327/380.

_eval_parivartana resolved "$a" / "$b" with ctx.resolve, which knows no
any_pair bindings, so raja_yoga_parivartana (kendra lord <-> trikona lord
exchange, BPHS 34.11) never fired. Bare "$x" refs now go through
_resolve_binding.

New test scans every custom expression for names the evaluator does not
define (only parvata_yoga, non-classical and left off, is excepted).
Neither file is in the rectification frozen identity; sealed 20/20 and
reported-offset 900/900 replay identical to moon_paksha_2026_11_04.

BUG-1570 (Aries / Scorpio Venus malefic by BPHS 34.20 / 34.35) and
BUG-1573 (packet members with no evaluable detector, no D9 context in the
consultation yoga path) are recorded, not changed: the BUG-1570 trial cut
reported-offset top-1 by 3-5 pp and needs a product decision.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 16:44:42 +08:00
ClaudeandClaude Opus 5.5 18b01c23e5 fix(shadbala): count the Moon's Paksha 2x, not 4x; adopt BPHS-Santhanam 27.10-11 + 27.18 (BUG-1557)
Independent Staging Quality Gate / publish (push) Canceled after 0s
Independent Staging Quality Gate / validate-python (push) Canceled after 1m32s
Independent Staging Quality Gate / validate-frontend (push) Canceled after 1m33s
The precise path doubled the Moon's Paksha in Kala (Raman, Graha and Bhava
Balas §55(c)) and then took that doubled value again as her Chesta (BPHS
27.18), so her Paksha entered the total four times; Chesta could reach 120,
clamping Kashta to 0 and pushing Ishta past 60. Every surveyed source
counts 2P.

Product decision 2026-11-04: BPHS (Santhanam) 27.10-11 + 27.18, as in
saravali.github.io, Maitreya8 (default) and jyotishyamitra. The Moon's
Paksha is the folded base, not doubled; waxing Moon benefic, waning Moon
malefic (BPHS 3.11, already what classify_drik_planets does, unchanged);
Chesta = Paksha. method_variants.moon_paksha names the convention. Other
planets, Drik and the legacy calc_kala_bala path are unchanged.

shadbala.py is in the rectification frozen identity, so per ERR-110 new
records were frozen and replayed as moon_paksha_2026_11_04. Compared field
by field with data_audit_2026_11_04: sealed holdout 20/20 and reported
offset 900/900 identical, metrics and summary unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 15:46:16 +08:00
ClaudeandClaude Opus 5.5 20a00ebef7 fix(dasha): continue Vimshottari past the first 120-year cycle (BUG-1556)
The first mahadasha starts before birth, so the nine periods end before the
120th birthday. Historical charts past that point had no covering period:
cmd_dasha's current_dasha was null and the consultation card's
timing.vimshottari was empty (Frida Kahlo at 2026-09-27).

next_cycle_mahadashas (chart_dasha/birth_moment.py) continues with the same
lords, order and full 365.25-day years until a period covers the reference
day; cmd_dasha, the chart surfaces and the consultation sub-periods share it.
Nothing is added inside the first cycle. The frozen rectification identity
(dasha_analyzer, domain_calculation_service) is untouched, so no re-freeze.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 14:54:19 +08:00
ClaudeandClaude Opus 5.5 1b367e6ba8 chore(rectification): re-freeze sealed holdout and offset sweep for the data-audit engine fixes (ERR-110)
Independent Staging Quality Gate / validate-frontend (push) Successful in 6m17s
Independent Staging Quality Gate / validate-python (push) Successful in 6m20s
Independent Staging Quality Gate / publish (push) Successful in 2m43s
BUG-1545 (scripts/narayana_dasha.py, scripts/active_rectification_event_engine.py)
and BUG-1546 (scripts/shadbala.py) changed files in the frozen scoring
identity, so the integrity gate went red. Per ERR-110, new records were
created with each script's --freeze and replayed under the label
data_audit_2026_11_04; the scripts, contract, freshness test and frontend
gate test now point at them, following 129313e1. Prior records are kept
byte-for-byte.

Compared field by field with the d60_mapping_2026_10_29 records:
- sealed holdout: 20/20 trials identical; metrics unchanged.
- reported offset: 898/900 identical; 2 trials changed true_rank only
  (one case, radius 60, offsets -30/-20: 76->67, 80->77). Top-1,
  minute error, delivery coverage and summary are unchanged. Reverting
  only the BUG-1545 files restores the old ranks; reverting shadbala.py
  does not; a different PYTHONHASHSEED gives the same result.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 14:13:00 +08:00
Claude f91608244a merge: upstream sync 10 into the data audit branch
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y

# Conflicts:
#	docs/BUG_HISTORY.md
2026-11-04 12:41:54 +08:00
ClaudeandClaude Opus 5.5 1c69c1b7e2 fix(chart): chart-page Shadbala takes the precise path readings use (BUG-1548)
The chart API called calc_shadbala without a context and so used the
simplified fallback, and it rewrote `degree` as the in-sign degree, which the
precise Dig bala reads as a longitude. Readings and reports took the precise
path, so the same chart showed different strengths and a different strongest
planet (Jobs: Moon 10.61 vs 6.61 Rupa). The endpoint now builds the same
context as cmd_shadbala and passes absolute longitudes; a test locks the two
equal per planet. Also records the astrologer's ruling on waning-Moon Paksha.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 12:33:23 +08:00
ClaudeandClaude Opus 5.5 7dcf8112ad fix(saham): natal Vivaha Saham uses the shared day/night rule (BUG-1547, upstream 26d5a52d)
The natal marriage point was hard-coded to Venus - Saturn + Asc with no
zodiacal-order exception, while the annual Tajika point already followed
references/saham_rules.json (PVR Table 74: night reverses the operands, plus
the +30 exception). The same night-born person had two marriage points; 6 of
the 9 public charts move. The full reading, the vivah-saham command and the
consult card now share tajika._formula_saham_trace, with day/night from the
card's own day_night evidence. 0 deg Aries is no longer "missing".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 12:23:21 +08:00
ClaudeandClaude Opus 5.5 9cd1e35f94 fix(shadbala): fold the Sun-Moon elongation before Paksha bala (BUG-1546)
abs(Sun - Moon) / 3 was never folded to 0-180 degrees, so on charts whose
raw difference passes 180 benefics got more than 60, malefics went negative
and the doubled Moon passed 120 (Monroe's Moon -45.76; 5 of 19 benchmark
charts). PyJHora has the same line, which is why the comparison agreed.

Same audit, no code change: the +/-60 Kala gap is PyJHora's hora formula;
PyJHora is the outlier on Mars/Jupiter/Venus Chesta; Sun/Moon Chesta is a
school difference. Shadbala totals stay off the card until those settle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 12:14:20 +08:00
ClaudeandClaude Opus 5.5 71510682dc fix(narayana): run the second cycle instead of replaying the first (BUG-1545)
The legacy current-period lookup took the age modulo the first-cycle total,
so anyone older than their first cycle (61-96 years on the nine public
charts) got a first-cycle period: an 80-year-old was placed in 2-12. The
second cycle runs the same signs for 12 minus their first-cycle years; the
lookup now places the age on both cycles and subdivides with the second
cycle's years. The rectification cache only covers the first cycle and falls
back to the live lookup past it, so first-cycle scoring is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 12:05:22 +08:00
ClaudeandClaude Opus 5.5 9d69cd5625 fix(kp): feed sub-lord analysis unrounded cusps, degrees and time (BUG-1543, upstream 26d5a52d)
cmd_kp handed calc_kp_analysis the cusps from calculate_bhava_boundaries
(rounded to 4 decimals), degree_in_sign (4 decimals) and the chart's
display julian_day (6 decimals). KP star, sub and sub-sub boundaries are
cut on raw longitude, so a body or cusp sitting on a boundary could land
one cell off. The fix recomputes the JD from the civil instant with the
compute_chart_data formula, uses calculate_cusps directly, and uses
degree_raw % 30.

Only the KP part of 26d5a52d is ported. Its Vivaha Saham day/night change
and Yoga status pass-through are left for a separate decision. Test ported
from upstream tests/test_kp_unrounded_inputs.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 12:01:47 +08:00
ClaudeandClaude Opus 5.5 8137c692b1 fix(full-reading): one observation date for Narayana, nakshatra and annual age (BUG-1542, upstream 933f254e)
today_str and transit_reference_date already followed transit_date, then
today, then now. Narayana's current period read only args.today, and the
nakshatra-dasha age and the annual fallback age used datetime.now(). A
dated report therefore mixed two dates. The annual fallback age also used
days // 365, which moves to the next year of age early.

All three now take the same observation date. The fallback age counts
calendar birthdays. Tests are ported from upstream
test_full_reading_observation_date.py and test_tajika_report_age.py and
adapted to cmd_full_reading. Same-day web consultations are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 12:00:44 +08:00
ClaudeandClaude Opus 5.5 4b6aa08726 fix(varga): count D12 linkage houses from the D12 ascendant (BUG-1541, upstream cf6c316d)
The full reading's inter-chart linkage appended D12 with a hard-coded None
ascendant, so every D12 row had house None even though d12_asc_idx was
already computed a few lines above. An unknown sign name also fell back to
Aries. Port upstream cf6c316d and f60568a0: pass d12_asc_idx through, and
raise on an unknown sign or a non 0-11 ascendant index. The full reading
records the error and the consult native layer marks it blocked.

Test ported from upstream tests/test_inter_chart_d12_house.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 11:59:33 +08:00
ClaudeandClaude Opus 5.5 297e27e0bd docs(privacy): swap the leftover private sample for upstream's public example
Upstream replaced the redacted-year sample (April 17, 14:45, about 36.5N
114.2E) with a public birth (1935-06-21 11:00, Cajarc, France) in the
reading workflow and in the narayana-dasha / solar-return usage text. Our
copies still carried the private date, time and place. The PDF guide's
example coordinates now name the San Francisco values it already labels.

Doc and docstring text only; no calculation changes. The same sample is
still a quality-gate fixture in scripts/run_quality_gate.py and appears in
older docs/research notes; neither is changed here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 11:54:12 +08:00
ClaudeandClaude Opus 5.5 3bae79fbca docs(upstream): mirror upstream SKILL.md at main 5fb8379c (sync 10)
Run scripts/import_yinduzhanxing.py --apply from a clean clone of upstream
main 5fb8379c, the upstream HEAD on 2026-11-04. Only the root SKILL.md
moves into references/upstream/yinduzhanxing; the six semantic-merge paths
stay review_required and untouched. The new mirror drops the private
"yn-1993" sample wording the b9a0ef8f mirror still carried.

source-manifest.json and import-plan.json now pin 5fb8379c. The b9a0ef8f
import record stays as history and its test now checks only the record.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 11:51:04 +08:00
ClaudeandClaude Opus 5.5 a14040c0d7 ci: balance the two validate jobs by moving the CLI smoke tests
Independent Staging Quality Gate / validate-python (push) Successful in 6m41s
Independent Staging Quality Gate / validate-frontend (push) Successful in 6m44s
Independent Staging Quality Gate / publish (push) Successful in 2m37s
After the fixture change validate-frontend finished ~3 min before
validate-python (307 s vs 491 s in run 6487). tests/test_cli_smoke.py
(~110 s) now runs in validate-frontend after the frontend suite, with the
same PYTHONPATH/PYTHON the gate sets. run_quality_gate.py gains
--exclude-pytest-target, which refuses anything not in the selected
targets; a test checks every exclusion is run by the other job.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-03 18:19:06 +08:00
ClaudeandClaude Opus 5.5 884a17997c ci: run the fragment audit once per quality gate
Independent Staging Quality Gate / validate-frontend (push) Successful in 5m7s
Independent Staging Quality Gate / validate-python (push) Successful in 8m11s
Independent Staging Quality Gate / publish (push) Successful in 2m31s
The gate ran scripts/audit_fragments.py --strict (~52 s on xiaoxin) and then
pytest ran the same audit() again in tests/test_api_server_security.py
(test_fragment_audit_blocks_registry_surface_drift asserts valid and more).
The separate step is gone; tests/test_quality_gate_fragment_audit_once.py,
now in the core targets, keeps the pytest copy and its target listing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-03 18:05:32 +08:00
ClaudeandClaude Opus 5.5 a861d26977 feat(chart): per-item birth-window stability, verify-first prompt, explicit calc settings (issue #165)
Part 2 of #144.
- The varga-segments scan gains opt-in stability_items: lagna degree, Sripati
  cusp signs, Moon sign / nakshatra / pada / house per minute, plus a
  historical-timezone check. The precheck requests D1/D9/D10 with it.
- Chart page shows nine computed items (一致 / 有变化) only for a range the
  user gave, the verbatim comparison sentence, a verify-first block for the
  conditions stored data can show, and the verbatim Dasha boundary sentence.
- Precheck sends the chart's ayanamsa and node mode and drops replies with
  other settings; the endpoint honours node_mode. candidate_time_sensitivity_scan
  and flexible_birth_time_profile take no defaults (BUG-1515).
- 只记得时辰 third question, stored in birth_time_clue; no migration.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-03 10:39:18 +08:00
ClaudeandClaude Opus 5.5 6e89ac175e fix(report): name the five-level sample 大运 / 小运 / 细运 / 微运 / 息运
Independent Staging Quality Gate / validate (push) Successful in 15m8s
Independent Staging Quality Gate / publish (push) Successful in 4m33s
Sookshma (subtle) becomes 微运 and Prana (breath) 息运, after their Sanskrit
sense, replacing the temporary Latin "Sookshma" header. Product, 2026-11-02.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-02 21:40:50 +08:00
ClaudeandClaude Opus 5.5 7d1057ccc5 feat(report): Vimshottari levels 大运 / 小运 / 细运 across the report pipeline
Independent Staging Quality Gate / validate (push) Successful in 21m50s
Independent Staging Quality Gate / publish (push) Successful in 4m21s
The personal report now uses the astrologer-approved names, matching the
chart page and the consult prompts since 7a56840f (issue #163 Q5): MD 大运,
AD 小运, PD 细运. Old names replaced in code-rendered text only: 主运 / 主大运
-> 大运, 子运 / 分运 / 副运 (AD) -> 小运, 次子运 / 次小运 / 再小运 and the
fact table's PD 小运 -> 细运. PD strings were converted before AD, and AD
before MD.

Covered: the focus card and its export text, the raw fact tables, theme
claim cards, the timing interpretation pack, the PL9 full-data export
(tables, dasha prose templates, AD/PD density anchors), rashi / Narayana
second level, KP monthly focus, orchestrator texts and technique-audit
rows. English translation keys follow the new Chinese labels
(大运 = Mahadasha, 小运 = Antardasha, 细运 = Pratyantardasha), and a new test
pins that no English mapping reads 小运 as the third level.

The five-level monthly sample table used 细运 for Sookshma; it now shows
Sookshma until the astrologer names the fourth level.

Saved reports are not migrated. Focus fences render from md/ad/pd codes,
and stored fact tables validate by structure, so old and new labels both
open. Goldens were updated in place and two hash pins re-pinned; reverting
only the term swap reproduces the old hashes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-02 21:32:51 +08:00