mirror of
https://github.com/tiennm99/miti99bot.git
synced 2026-09-04 04:18:08 +00:00
docs: add amlich improvement research, brainstorm decision, and completed plan
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
---
|
||||
phase: 1
|
||||
title: Lunar core helpers
|
||||
status: completed
|
||||
effort: S
|
||||
priority: P2
|
||||
dependencies: []
|
||||
---
|
||||
|
||||
# Phase 1: Lunar core helpers
|
||||
|
||||
## Overview
|
||||
|
||||
Add the two pure helpers the handlers need: the disputed-boundary set + membership check, and
|
||||
leap-month existence probing. No behavior change to existing conversion functions.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Functional: `nearDisputedBoundary(jdn int) bool` reports whether the lunar month containing
|
||||
solar day `jdn` starts or ends on one of the 7 disputed month boundaries.
|
||||
- Leap-variant existence needs NO new helper: handlers probe `lunarToSolar(day, month, year, true)`
|
||||
and treat `err == nil` as "leap variant exists" (DRY — reuses existing validation; also naturally
|
||||
suppresses the hint when e.g. day 30 doesn't exist in the 29-day leap month).
|
||||
- Non-functional: helpers stay in `lunar.go`, unexported, zero allocations on the hot path
|
||||
(package-level set built once).
|
||||
|
||||
## Architecture
|
||||
|
||||
- `disputedMonthStarts` — package-level `map[int]bool` built in a `var` initializer from
|
||||
`jdFromDate` on the 7 dates recorded in `docs/amlich-known-issues.md`:
|
||||
09/12/2072, 15/11/2077, 07/05/2130, 26/05/2150, 17/05/2159, 22/01/2175, 26/01/2199.
|
||||
- `nearDisputedBoundary(jdn int) bool` — mirror `solarToLunar`'s month-start search:
|
||||
|
||||
```go
|
||||
k := floorInt((float64(jdn) - jdNewMoonEpoch) / newMoonCycle)
|
||||
monthStart := getNewMoonDay(k + 1)
|
||||
for monthStart > jdn {
|
||||
k--
|
||||
monthStart = getNewMoonDay(k + 1)
|
||||
}
|
||||
return disputedMonthStarts[monthStart] || disputedMonthStarts[getNewMoonDay(k+2)]
|
||||
```
|
||||
|
||||
Rationale for checking next start too: if the *end* boundary of the containing month is disputed,
|
||||
the month's length (and day numbers near its end) is what may shift.
|
||||
|
||||
## Related Code Files
|
||||
|
||||
- Modify: `internal/modules/amlich/lunar.go`
|
||||
- Modify: `internal/modules/amlich/lunar_test.go`
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
1. Add `disputedMonthStarts` set with a comment explaining provenance (new moon within ±2 min of
|
||||
UTC+7 midnight; see docs/amlich-known-issues.md) — no plan/audit labels in comments.
|
||||
2. Add `nearDisputedBoundary`.
|
||||
3. Test: each of the 7 JDs is an actual month start per the engine — for each date, assert
|
||||
`solarToLunar(d,m,y)` returns lunar day 1. If any assertion fails ±1 day, the doc date and the
|
||||
engine's boundary disagree: adjust the set entry to the engine's month start and flag the doc
|
||||
discrepancy in the phase report.
|
||||
4. Test `nearDisputedBoundary`: true for a mid-month day of the month starting 09/12/2072, true for
|
||||
a day in the month *before* it (whose end boundary is disputed), false for an ordinary 2072 date
|
||||
far from the boundary and for a 2024 date.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- [ ] 7 set entries verified as engine month starts by test
|
||||
- [ ] `nearDisputedBoundary` true/false cases covered as above
|
||||
- [ ] Existing lunar tests untouched and green
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
- Doc dates might be the full-Meeus engine's boundaries rather than the current engine's (off by
|
||||
one day). Mitigation: step 3's pin test resolves it mechanically; the ±1-day neighborhood is the
|
||||
same disputed lunation either way.
|
||||
@@ -0,0 +1,66 @@
|
||||
---
|
||||
phase: 2
|
||||
title: Handler replies
|
||||
status: completed
|
||||
effort: S
|
||||
priority: P2
|
||||
dependencies:
|
||||
- 1
|
||||
---
|
||||
|
||||
# Phase 2: Handler replies
|
||||
|
||||
## Overview
|
||||
|
||||
Wire the leap-month hint into `/duonglich` and the razor-edge caveat into both commands. Reply
|
||||
sentences gain optional trailing lines only; existing first-line format is unchanged.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Functional (`/duonglich` hint): after a successful conversion with `leap == false`, if
|
||||
`lunarToSolar(day, month, year, true)` returns nil error, append:
|
||||
`Lưu ý: năm âm lịch <year> có tháng <month> nhuận — thêm "nhuan" nếu ý bạn là tháng nhuận.`
|
||||
- Functional (caveat, both commands): if `nearDisputedBoundary(jd)` — where `jd` is the *solar* JD
|
||||
of the queried/resulting date — append:
|
||||
`Lưu ý: ngày này gần ranh giới tháng âm lịch chưa chắc chắn; kết quả có thể lệch 1 ngày so với lịch chính thức sau này.`
|
||||
- Hint NOT shown when `nhuan` was explicit (user already disambiguated) or when the exact leap date
|
||||
doesn't exist. Both lines may co-occur (hint first, then caveat), each on its own line after the
|
||||
main sentence, separated by `\n`.
|
||||
- Non-functional: no change to usage strings, error paths, or year-range checks.
|
||||
|
||||
## Architecture
|
||||
|
||||
- `/amlich`: `jd := jdFromDate(day, month, year)` (already-parsed solar input) → caveat check.
|
||||
- `/duonglich`: caveat check on `jdFromDate(solarDay, solarMonth, solarYear)` from the conversion
|
||||
result; hint check via the leap-variant probe before assembling the reply.
|
||||
- Message constants live next to the usage constants in `handlers.go`.
|
||||
|
||||
## Related Code Files
|
||||
|
||||
- Modify: `internal/modules/amlich/handlers.go`
|
||||
- Modify: `internal/modules/amlich/handlers_test.go`
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
1. Add the two message constants (hint as format string taking year + month).
|
||||
2. `/duonglich`: after successful `lunarToSolar`, build reply, conditionally append hint (probe
|
||||
with `leap=true` only when input `leap == false`), then conditionally append caveat.
|
||||
3. `/amlich`: conditionally append caveat after the main sentence.
|
||||
4. Tests (extend existing fake-reply pattern in `handlers_test.go`):
|
||||
- `/duonglich 5/5/2028` → hint present (2028 has leap 5); `/duonglich 5/5/2028 nhuan` → absent;
|
||||
`/duonglich 5/5/2027` → absent (no leap 5 in 2027).
|
||||
- `/amlich` on a date inside the disputed month at 09/12/2072 → caveat present; ordinary date →
|
||||
absent. `/duonglich` case whose result lands in that month → caveat present.
|
||||
- Assert exact full reply strings (repo test style asserts exact text — keep it strict).
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- [ ] Hint behavior matches the three `/duonglich` cases above
|
||||
- [ ] Caveat fires for disputed-month dates in both commands, silent elsewhere
|
||||
- [ ] All pre-existing handler tests pass without assertion loosening
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
- Double-probe cost: one extra `lunarToSolar` call per leap-year query — microseconds, irrelevant.
|
||||
- Wording is user-visible contract; if the user wants different Vietnamese phrasing, only the
|
||||
constants change. Flag wording in the PR description for review.
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
---
|
||||
phase: 3
|
||||
title: Golden-table testdata and docs
|
||||
status: completed
|
||||
effort: S
|
||||
priority: P3
|
||||
dependencies: []
|
||||
---
|
||||
|
||||
# Phase 3: Golden-table testdata and docs
|
||||
|
||||
## Overview
|
||||
|
||||
Freeze the verified 1800–2199 month structure as committed testdata, and close the resolved open
|
||||
questions in `docs/amlich-known-issues.md`. Independent of phases 1–2.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Functional: a test recomputes every lunar year's structure from the engine and compares
|
||||
byte-exact against `testdata/lunar-years-1800-2199.txt`; `go test -run TestGoldenTable -update`
|
||||
regenerates the file (standard `-update` flag idiom).
|
||||
- File format, one line per lunar year:
|
||||
`YYYY L n1 n2 ... nN` — `L` = leap month number (0 = none), `n*` = month lengths (29/30) in
|
||||
chronological order, tháng 1 first, leap month inserted in sequence after month `L`
|
||||
(12 entries normal year, 13 leap year).
|
||||
- Non-functional: file lives in `internal/modules/amlich/testdata/`; generation logic lives in the
|
||||
test file only (no production code).
|
||||
|
||||
## Architecture
|
||||
|
||||
- Build each year from `lunarToSolar` month starts: for lunar year Y, JDs of tháng 1..12 (+ leap
|
||||
where `lunarToSolar(1, m, Y, true)` succeeds), sorted chronologically; lengths = successive
|
||||
start-JD differences, last month's length from tháng 1 of Y+1. Simpler than sweeping days and
|
||||
exercises the lunar→solar direction the round-trip test already covers from the other side.
|
||||
- Rationale over round-trip: `TestSolarLunarRoundTrip` proves self-consistency only; a future
|
||||
engine change that shifts a boundary consistently in both conversions passes it. The golden file
|
||||
pins the actual verified placement.
|
||||
|
||||
## Related Code Files
|
||||
|
||||
- Create: `internal/modules/amlich/testdata/lunar-years-1800-2199.txt`
|
||||
- Modify: `internal/modules/amlich/lunar_test.go` (or new `golden_test.go` if it crowds the file)
|
||||
- Modify: `docs/amlich-known-issues.md`
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
1. Write `TestGoldenTable` with `var update = flag.Bool("update", false, ...)`; generator builds the
|
||||
full table string; when `-update`, write file and skip compare; else compare byte-exact with a
|
||||
diff-friendly failure message (first differing line).
|
||||
2. Generate the file once; eyeball spot checks: 2025 leap 6, 2028 leap 5, 2033 leap 11, 1944
|
||||
leap 4, 1967 no leap month (leap numbers already pinned by `TestLeapMonthTable` — must agree;
|
||||
the doc's "30/5 Đinh Mùi" for 1967 is day 30 of the regular month 5, not a leap month).
|
||||
3. Commit the generated file. Edge-case years must round-trip with the existing suite untouched.
|
||||
4. Update `docs/amlich-known-issues.md`:
|
||||
- Open question 1 → resolved: caveat line added, months touching the boundary only.
|
||||
- Open question 2 → closed (don't build): add the South-Vietnam wrinkle (UTC+7 until 1959,
|
||||
UTC+8 1960–67 per Hồ Ngọc Đức's historic-calendar page) — a single UTC+8 mode would be wrong
|
||||
for the South 1955–59, strengthening the existing conclusion.
|
||||
- "`/duonglich` defaults inside leap months" item → note the hint now self-disambiguates.
|
||||
- Keep questions 3 (ΔT) and 4 (future official tables) open; add one line noting the 2026 CGPM
|
||||
leap-second-abolition vote as a further far-future timescale uncertainty in the same bucket.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- [ ] Golden file committed; regeneration from HEAD is byte-identical
|
||||
- [ ] Golden leap months agree with `TestLeapMonthTable` pins
|
||||
- [ ] Docs updated; no stale claims left in the two resolved items
|
||||
- [ ] `docs/amlich-known-issues.md` stays under docs.maxLoc (800)
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
- Ordering bug when inserting the leap month (nhuận m sorts after regular m) — chronological
|
||||
sort by start JD avoids hand-rolled index math.
|
||||
- `flag.Bool` at package scope collides if a flag named `update` ever exists elsewhere in the
|
||||
package's tests — it doesn't today; keep the name.
|
||||
@@ -0,0 +1,64 @@
|
||||
---
|
||||
title: >-
|
||||
Amlich converter improvements: leap-month hint, razor-edge caveat,
|
||||
golden-table tests
|
||||
description: >-
|
||||
Three merged non-breaking improvements to internal/modules/amlich from
|
||||
brainstorm decision
|
||||
status: completed
|
||||
priority: P2
|
||||
branch: main
|
||||
tags:
|
||||
- amlich
|
||||
- telegram-bot
|
||||
blockedBy: []
|
||||
blocks: []
|
||||
created: '2026-08-18T15:04:11.318Z'
|
||||
createdBy: 'ck:plan'
|
||||
source: skill
|
||||
---
|
||||
|
||||
# Amlich converter improvements: leap-month hint, razor-edge caveat, golden-table tests
|
||||
|
||||
## Overview
|
||||
|
||||
Implement the three improvements selected in
|
||||
`plans/reports/brainstorm-decision-260818-2158-amlich-improvements-selection-report.md`
|
||||
(research: `plans/reports/research-brainstorm-260818-2147-amlich-converter-improvements-report.md`):
|
||||
|
||||
1. `/duonglich` leap-month ambiguity hint — when the entered month is also that year's leap month
|
||||
and no `nhuan` flag given, append a one-line hint.
|
||||
2. Razor-edge caveat — both commands warn when the result's lunar month touches one of the 7
|
||||
disputed month boundaries from 2072 on (documented in `docs/amlich-known-issues.md`).
|
||||
3. Golden-table regression testdata — freeze the verified 1800–2199 month-structure output.
|
||||
|
||||
Explicitly out of scope (rejected with verification in the research report): ΔT model update,
|
||||
pre-1968 historic mode, table-driven engine rewrite, range extension, extra calendar features.
|
||||
|
||||
## Phases
|
||||
|
||||
| Phase | Name | Status |
|
||||
|-------|------|--------|
|
||||
| 1 | [Lunar core helpers](./phase-01-lunar-core-helpers.md) | Completed |
|
||||
| 2 | [Handler replies](./phase-02-handler-replies.md) | Completed |
|
||||
| 3 | [Golden-table testdata and docs](./phase-03-golden-table-testdata-and-docs.md) | Completed |
|
||||
|
||||
## Dependencies
|
||||
|
||||
None cross-plan. Phase 2 depends on phase 1; phase 3 is independent.
|
||||
|
||||
## Acceptance Criteria (whole plan)
|
||||
|
||||
- All existing tests pass unchanged — especially `knownDates` pins (20/6/1944, 7/7/1967),
|
||||
`TestSolarLunarRoundTrip`, `TestLeapMonthTable`.
|
||||
- `/duonglich 5/5/2028` (leap-5 year) shows the hint; `/duonglich 5/5/2028 nhuan` and non-leap
|
||||
years do not.
|
||||
- Conversions inside a lunar month adjacent to the 09/12/2072 boundary show the caveat (both
|
||||
commands); ordinary dates do not.
|
||||
- Golden file regenerated from HEAD is byte-identical to the committed one.
|
||||
- No public-contract changes; reply format only gains optional trailing lines.
|
||||
- `go vet ./...` and `staticcheck` clean (repo standard).
|
||||
|
||||
## Validation
|
||||
|
||||
`go test ./internal/modules/amlich/` after each phase; full `go test ./...` + lint at the end.
|
||||
@@ -0,0 +1,72 @@
|
||||
# Brainstorm Decision: amlich Converter Improvements — Selected Scope
|
||||
|
||||
Date: 2026-08-18 21:58 (+07)
|
||||
Basis: `plans/reports/research-brainstorm-260818-2147-amlich-converter-improvements-report.md`
|
||||
Mode: user delegated choice ("choose the best, merge if mergable").
|
||||
|
||||
## Decision
|
||||
|
||||
All three recommended items merged into one change set — they are complementary (input UX,
|
||||
output honesty, test hardening), not alternatives. Rejections from the research report stand.
|
||||
|
||||
### In scope
|
||||
|
||||
1. **Leap-month hint in `/duonglich`** (highest user value, do first)
|
||||
- Trigger: resolved month == that lunar year's leap month AND `nhuan` flag absent.
|
||||
- Output: append "Năm nay có tháng X nhuận — thêm 'nhuan' nếu ý bạn là tháng nhuận."
|
||||
- Impl: `leapMonthOf(year int) (month int, ok bool)` helper in `lunar.go` reusing
|
||||
`getLunarMonth11` + `getLeapMonthOffset`; hint assembled in `handlers.go`.
|
||||
- NOT triggered when `nhuan` explicit (resolves research report open question 2: no).
|
||||
|
||||
2. **Razor-edge caveat in both commands**
|
||||
- Data: 7 disputed month-start JDs (new moons of 09/12/2072, 15/11/2077, 07/05/2130,
|
||||
26/05/2150, 17/05/2159, 22/01/2175, 26/01/2199) as a package-level set in `lunar.go`,
|
||||
JD values derived at implementation time and pinned by test.
|
||||
- Trigger: containing month start OR next month start is in the set → append one-line
|
||||
caveat: result near disputed lunar-month boundary, may differ ±1 day from future
|
||||
official tables.
|
||||
- Scope: months touching the boundary only, not the whole lunar year (resolves research
|
||||
report open question 1: months-only; year-wide is alarmist).
|
||||
- Impl: `nearDisputedBoundary(jdn int) bool` helper; handlers call it with the solar JD.
|
||||
|
||||
3. **Golden-table regression testdata**
|
||||
- `internal/modules/amlich/testdata/lunar-years-1800-2199.txt`: one line per year —
|
||||
year, leap-month index (0 = none), month lengths in order (12 or 13 entries).
|
||||
- Test recomputes from engine, compares byte-exact; `-update` flag idiom regenerates.
|
||||
- Rationale: round-trip test proves self-consistency only; golden table freezes the
|
||||
verified boundary placement against silent drift.
|
||||
|
||||
### Out of scope (rejected, verified in research report)
|
||||
|
||||
- ΔT model update — breaks bit-compatibility with ecosystem; verified by prior 400-year diff.
|
||||
- Pre-1968 historic mode — ground truth fragments (North UTC+8 1945–67; South UTC+7→UTC+8 1960).
|
||||
- Table-driven engine rewrite — no authoritative source beyond current engine; test-data-only instead.
|
||||
- Range extension beyond 1800–2199; can-chi day names, tiết khí, holiday lookup.
|
||||
|
||||
## Touchpoints
|
||||
|
||||
- `internal/modules/amlich/lunar.go` — `leapMonthOf`, `nearDisputedBoundary`, disputed-JD set.
|
||||
- `internal/modules/amlich/handlers.go` — hint + caveat lines in both command replies.
|
||||
- `internal/modules/amlich/lunar_test.go`, `handlers_test.go` — new cases; existing pins untouched.
|
||||
- `internal/modules/amlich/testdata/` — new golden file.
|
||||
- `docs/amlich-known-issues.md` — close open questions 1–2 with these resolutions.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- All existing tests pass unchanged, incl. `knownDates` (20/6/1944, 7/7/1967) and full round-trip.
|
||||
- `/duonglich 5/5/2028` (leap-5 year) shows hint; `/duonglich 5/5/2028 nhuan` and non-leap years don't.
|
||||
- `/amlich` for a date inside a month adjacent to 09/12/2072 boundary shows caveat; ordinary dates don't;
|
||||
`/duonglich` symmetric.
|
||||
- Golden file regenerated from HEAD is byte-identical to committed version.
|
||||
- ~100 LOC total incl. tests; no public-contract changes.
|
||||
|
||||
## Risks
|
||||
|
||||
- Caveat JD derivation error → wrong months flagged. Mitigation: pin the 7 JDs in a test that
|
||||
recomputes them from `getNewMoonDay`.
|
||||
- Reply strings are user-visible contract for handler tests — update expected strings, don't loosen asserts.
|
||||
|
||||
## Unresolved Questions
|
||||
|
||||
- None blocking. Post-leap-second timescale question stays parked in `docs/amlich-known-issues.md`
|
||||
open question 4.
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
# Research + Brainstorm Report: Improving the amlich/duonglich Converter
|
||||
|
||||
Date: 2026-08-18 21:47 (+07)
|
||||
Scope: `internal/modules/amlich` — what improvements remain, ranked; what to explicitly reject.
|
||||
Inputs: repo code + `docs/amlich-known-issues.md` (prior 400-year Meeus-vs-HND diff), 5 web lookups (2 WebSearch, 3 WebFetch).
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Algorithm question is settled and should stay settled: the truncated Hồ Ngọc Đức port is bit-compatible
|
||||
with the de-facto Vietnamese ecosystem and empirically beat a full Meeus ch.49 engine on both
|
||||
historically verifiable razor-edge dates. No engine change is justified by any new evidence found.
|
||||
|
||||
Remaining improvement space is small and mostly UX/honesty, not math:
|
||||
(1) caveat line for the 7 razor-edge lunations 2072+, (2) leap-month ambiguity hint in `/duonglich`,
|
||||
(3) optional golden-table regression hardening. Everything else researched — ΔT model update,
|
||||
pre-1968 historic mode, table-driven rewrite, range extension — should be rejected; reasons below.
|
||||
|
||||
## New Research Findings (2026)
|
||||
|
||||
- **ΔT trend confirms doc's suspicion, changes nothing.** Earth set rotation-speed records in 2024–2025;
|
||||
IERS added no leap second in 2024; ~30% chance of a first-ever *negative* leap second before 2035.
|
||||
ΔT is flat-to-declining vs the polynomial's predicted growth — so the code's ΔT branch overestimates
|
||||
future ΔT. But this only matters inside the already-documented razor-edge windows. See "Reject: ΔT".
|
||||
- **Leap-second abolition adds a *new* far-future uncertainty.** CGPM votes Oct 2026 to replace the leap
|
||||
second (possibly retiring it as early as 2027). If UTC stops tracking UT1, civil UTC+7 slowly drifts
|
||||
from the astronomical time the algorithm models — same bucket as ΔT: only razor-edge relevant,
|
||||
unresolvable until Vietnam's authorities say which timescale the calendar follows.
|
||||
- **No official Vietnamese tables exist past ~2100.** Nothing from a state calendar bureau covering
|
||||
2072+ disputes surfaced. Hồ Ngọc Đức remains the de-facto ground truth; his site claims historic
|
||||
reliability "since 1301" and notes official/astronomical calendars coincide since 1976.
|
||||
- **Pre-1968 is messier than "UTC+8".** Per HND's historic-calendar page: North used UTC+8 1945–67;
|
||||
South used UTC+7 until 1959 then UTC+8 1960–67; pre-1945 rests on dynastic tables (Bách trúng kinh
|
||||
1624–1799, Khâm định vạn niên thư 1554–1903). A single "UTC+8 historic mode" (open question 2 in
|
||||
known-issues) would be *wrong for South Vietnam 1955–59* — the idea is even weaker than documented.
|
||||
- **Go ecosystem check.** Other Go ports (hungtrd/amlich, buichuongvnua/amlich, go-dyn/vcalendar) are
|
||||
straight HND ports without the day-0 overshoot fix or input validation this repo already has.
|
||||
Nothing to borrow; this implementation is ahead of them.
|
||||
|
||||
## Brainstorm: Evaluated Approaches
|
||||
|
||||
### Recommend — small, honest, non-breaking
|
||||
|
||||
**1. Razor-edge caveat in bot replies** (resolves known-issues open question 1)
|
||||
- What: hardcode the 7 disputed month-boundary JDs (09/12/2072, 15/11/2077, 07/05/2130, 26/05/2150,
|
||||
17/05/2159, 22/01/2175, 26/01/2199). When a conversion's month start or next-month start is one of
|
||||
them, append one line: result near a disputed lunar-month boundary, may differ ±1 day from future
|
||||
official tables.
|
||||
- Affects ~413 of 146,097 days; zero risk to correct output; converts a silent known-wrongness into
|
||||
stated uncertainty. Cost: a small table + one condition + tests.
|
||||
- Trade-off: nobody realistically queries 2130 from a Telegram bot — pure-YAGNI reading says skip.
|
||||
But the cost is ~30 LOC and it closes a documented open question permanently.
|
||||
|
||||
**2. Leap-month ambiguity hint in `/duonglich`** (fixes the "correct output reported as bug" item)
|
||||
- What: when the resolved (possibly defaulted) month equals that lunar year's leap month and no
|
||||
`nhuan` flag was given, append a hint: "Năm nay có tháng X nhuận — thêm 'nhuan' nếu ý bạn là
|
||||
tháng nhuận." Detection is one `getLeapMonthOffset` call on the already-computed a11.
|
||||
- Alternatives considered: (a) reply with *both* conversions — noisier, two answers where user wants
|
||||
one; (b) leave as-is — keeps a documented user-confusion source. Hint is the KISS winner:
|
||||
single authoritative answer + self-service disambiguation.
|
||||
|
||||
**3. Golden-table regression corpus** (optional hardening)
|
||||
- What: generate once, from the current verified engine, a compact per-year record (leap-month index +
|
||||
12/13 month lengths) for all 400 years; commit as testdata; test decodes and compares.
|
||||
- Why round-trip isn't enough: `TestSolarLunarRoundTrip` proves *self-consistency*; a future change
|
||||
could shift a month boundary consistently in both directions and pass. `knownDates` +
|
||||
`TestLeapMonthTable` pin samples only. A golden table freezes the full verified behavior and makes
|
||||
any future engine experiment a reviewable one-file diff.
|
||||
- Cost: ~1 generator run + ~4 KB testdata + one test. Verdict: worth it, do alongside #1.
|
||||
|
||||
### Reject — with reasons pinned
|
||||
|
||||
**ΔT model update.** New IERS data makes the polynomial *more* wrong, yet updating it is still wrong to
|
||||
do: the module's value is bit-compatibility with the reference algorithm every Vietnamese app runs.
|
||||
A "better" ΔT flips razor-edge dates away from ecosystem consensus → user-visible mismatches
|
||||
reported as bugs, with no authority to say we're right. Revisit only if official 2072+ tables appear
|
||||
(known-issues open question 4). Approach #1 (caveat) is the correct treatment of this uncertainty.
|
||||
|
||||
**Pre-1968 historic mode.** Ground truth fragments by government (North/South differ 1955–67, dynastic
|
||||
before 1945); a correct implementation is a research project, not a module feature; the proleptic
|
||||
astronomical calendar is what every reference source shows for those years anyway. Current behavior
|
||||
already matches the published record on both verifiable disputes. Keep documented, don't build.
|
||||
This *strengthens* the known-issues answer to open question 2: even a user-reported mismatch should
|
||||
trigger a doc note, not a UTC+8 mode.
|
||||
|
||||
**Table-driven rewrite.** A table must be generated from something. From this engine → just a cache of
|
||||
identical output (Go float64 JD math has ~4.5e-10-day ulp vs 0.0014-day decision margins; no
|
||||
platform-flip risk to cache away). From official tables → they don't exist past ~2100. Table-driven
|
||||
is how you'd start from scratch; with a verified engine it adds a second representation to keep in
|
||||
sync (DRY violation) for zero accuracy. The useful 20% of this idea is #3 (table as *test* data).
|
||||
|
||||
**Range extension beyond 1800–2199.** Bound exists because published references stop there; claims
|
||||
outside are unverifiable. Nothing found changes that.
|
||||
|
||||
**Feature creep** (ngày can-chi, tiết khí, giờ hoàng đạo, holiday lookup): out of scope until a user
|
||||
asks. Noted so it isn't re-brainstormed.
|
||||
|
||||
## Success Criteria (if #1–#3 are implemented)
|
||||
|
||||
- All existing tests pass unchanged, incl. `knownDates` pins (20/6/1944, 7/7/1967).
|
||||
- Caveat appears for a 2072+ razor-edge date, absent for ordinary dates (both directions of conversion).
|
||||
- `/duonglich 5/5/2028` (leap-5 year) shows hint; `/duonglich 5/5/2028 nhuan` and non-leap years don't.
|
||||
- Golden table regenerated from HEAD is byte-identical to committed testdata.
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Decide which of #1/#2/#3 to implement (recommendation: all three; #2 first — most user-visible).
|
||||
2. `/ck:plan` with this report as context if proceeding; scope is small enough for a single phase.
|
||||
3. Update `docs/amlich-known-issues.md` open questions 1–3 with the resolutions above once implemented.
|
||||
|
||||
## Sources
|
||||
|
||||
- [Hồ Ngọc Đức — Vietnamese lunar calendar](https://www.xemamlich.uhm.vn/vncal_en.html)
|
||||
- [Hồ Ngọc Đức — Historic Vietnamese lunar calendar](https://www.xemamlich.uhm.vn/histcal.html)
|
||||
- [Vietnamese calendar — Wikipedia](https://en.wikipedia.org/wiki/Vietnamese_calendar)
|
||||
- [IERS: no leap second in 2024 — DCD](https://www.datacenterdynamics.com/en/news/no-leap-seconds-added-to-universal-time-in-2024-iers-says/)
|
||||
- [Earth rotation records spur Oct 2026 CGPM vote — TechTimes](https://www.techtimes.com/articles/320185/20260711/earth-rotation-records-spur-october-vote-avert-negative-leap-second.htm)
|
||||
- [Negative leap second outlook — timeanddate](https://www.timeanddate.com/time/negative-leap-second-maybe.html)
|
||||
- [Earth rotation acceleration analysis — Astronomy Reports 2024](https://arxiv.org/html/2404.06343v3)
|
||||
- Go ports surveyed: [hungtrd/amlich](https://github.com/hungtrd/amlich), [buichuongvnua/amlich](https://pkg.go.dev/github.com/buichuongvnua/amlich), [go-dyn/vcalendar](https://pkg.go.dev/github.com/go-dyn/vcalendar)
|
||||
|
||||
## Unresolved Questions
|
||||
|
||||
1. Caveat wording/threshold for #1: flag only the two months touching a disputed boundary (proposed),
|
||||
or the whole lunar year? Proposed: months only — year-wide is alarmist.
|
||||
2. Should the leap-month hint (#2) also fire when month+`nhuan` *was* given but the defaulted year
|
||||
was filled in (user may have meant a different year)? Proposed: no — over-engineering.
|
||||
3. If leap seconds are abolished (Oct 2026 vote), does Vietnam's calendar follow civil UTC+7 or
|
||||
UT1+7? Unanswerable today; park with known-issues open question 4.
|
||||
Reference in New Issue
Block a user