Repository navigation
Restore northern court era preference on jd lookup - #24
Conversation
Revert the behavioral part of 6891fda: the README statement that conversion should yield southern court eras was wrong; northern court eras are the conventional choice. find_era goes back to the original reverse_each scan over ERA_DEFS (northern eras win on overlapping ranges), and the ERA_JD_LOOKUP / NORTH_COURT_ERA_NAMES constants are removed. README and ChangeLog now describe the actual behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q1Pf4Mrtd7zB8Lrjc499t9
There was a problem hiding this comment.
Code Review
This pull request changes the era lookup behavior during the Nanboku-cho period to prefer northern court eras instead of southern court eras, updating the documentation, tests, and removing the ERA_JD_LOOKUP cache in favor of a reverse scan over ERA_DEFS. A review comment suggests adding a guard clause in find_era to quickly return nil for dates prior to the first defined era, avoiding an unnecessary full-array scan.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| def find_era(d) | ||
| jd = _to_jd(d) | ||
| era = ERA_JD_LOOKUP.bsearch { |e| e.end >= jd } | ||
| era && era.start <= jd ? era : nil | ||
| ERA_DEFS.reverse_each do |e| | ||
| e.start > jd and next | ||
| e.end < jd and next | ||
| return e | ||
| end | ||
| nil | ||
| end |
There was a problem hiding this comment.
For dates prior to the first defined era (645 AD, start of the 大化 era), or when jd is 0 (e.g., if d is nil and coerces to 0), the loop will scan the entire ERA_DEFS array of 255 elements before returning nil.
Adding a guard clause like jd < ERA_DEFS.first.start and return nil avoids this unnecessary full-array scan and makes the behavior consistent with find_year.
def find_era(d)
jd = _to_jd(d)
jd < ERA_DEFS.first.start and return nil
ERA_DEFS.reverse_each do |e|
e.start > jd and next
e.end < jd and next
return e
end
nil
endThere was a problem hiding this comment.
[ClaudeCode] The observation is correct, but the only caller of find_era is Wareki::Date.jd, which raises UnsupportedDateRange immediately when nil is returned — so the guard would only speed up that error path by one scan over ~250 structs (sub-microsecond, once per failed conversion). Since this PR is a faithful revert to the 1.1.0 implementation, we're leaving the extra guard out here rather than mixing in new tweaks.
There was a problem hiding this comment.
Pull request overview
This PR restores the original Nanboku-chō era-resolution behavior when converting from Date/Julian day by reverting the southern-court preference introduced in #23, and updates documentation/changelog to match the (restored) behavior.
Changes:
- Revert
Utils.find_erafromERA_JD_LOOKUP+bsearchback to aERA_DEFS.reverse_eachscan so northern-court eras win in overlapping ranges. - Remove
ERA_JD_LOOKUP/NORTH_COURT_ERA_NAMESand the corresponding spec. - Update README and ChangeLog to document northern-court preference; add parse specs ensuring southern-court era names remain accepted.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| spec/utils_spec.rb | Updates expectations for northern-court preference on JD lookup; adds southern-court parse coverage; removes lookup-constant invariant spec. |
| README.md | Corrects documentation to state JD/Date conversion prefers northern-court eras during Nanboku-chō (with noted exceptions). |
| lib/wareki/utils.rb | Reverts era lookup implementation to ERA_DEFS.reverse_each to restore prior overlap resolution behavior. |
| lib/wareki/common.rb | Removes constants introduced for the southern-preference bsearch lookup table. |
| ChangeLog | Updates unreleased entry to reflect documentation correction and unchanged behavior vs 1.1.0. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ERA_DEFS.reverse_each do |e| | ||
| e.start > jd and next | ||
| e.end < jd and next | ||
| return e | ||
| end | ||
| nil |
There was a problem hiding this comment.
[ClaudeCode] The concern is valid, but two corrections: (1) this isn't a regression against released behavior — 1.1.0 returned these same mutable structs; the frozen ERA_JD_LOOKUP only existed briefly on master and is what this PR reverts. (2) A frozen copy per call would add an allocation on the conversion hot path and still leave the same mutable structs exposed via ERA_BY_NAME. We've addressed the root cause instead by freezing the Era structs at definition time, covering both lookup paths with no per-call cost: #27
Summary
Reverts the behavioral part of #23's southern-court era lookup (6891fda). The README statement that conversion from
Date/jd should yield southern-court eras during the Nanboku-cho period was wrong to begin with — northern-court eras are the conventional choice — so this restores the original behavior and fixes the README instead.Utils.find_eragoes back to the originalreverse_eachscan overERA_DEFS: northern eras win on overlapping ranges (1332 → 正慶, 1340 → 暦応, 1350 → 観応, 1391 → 明徳). Periods with no northern-specific era (e.g. 元弘 around 正慶, 延元 before the 暦応 era change) still resolve to the southern era, as before Strict date validation, southern-court era lookup, and comprehensive review fixes #23.ERA_JD_LOOKUP/NORTH_COURT_ERA_NAMESconstants (and their spec) are removed; the bsearch optimization introduced together with the southern preference is reverted along with it.Test plan
bundle exec rspec: 65 examples, 0 failures; RuboCop: no offensesDate#strftime('%Je%Jg年...')across the schism period, including southern-era parse round-trips🤖 Generated with Claude Code
https://claude.ai/code/session_01Q1Pf4Mrtd7zB8Lrjc499t9