fuzzyworld

when-am-i / files / .claude / skills / new-calendar / SKILL.md

SKILL.md

Blame: the commit that last changed each line · file · history

4a2e1dbe 2026-06-21 Pavel Safronov1---
2name: new-calendar
3description: Author a new calendar region dataset file for "When am I?" end-to-end — research a place/people's calendar system(s) with sourced citations, draft the GeoJSON region polygon and eras with proleptic-Gregorian dates, choose the right converter (or descriptive-only), then validate, screenshot, and prepare a PR-ready contribution. Use when adding a calendar/region, contributing calendar data, or extending coverage to a new place or people.
4---
5
6# Authoring a new calendar dataset
7
8This skill walks you through creating one `src/data/calendars/<slug>.json` region
9file for the "When am I?" app, the way a careful contributor would. The app's
10framing is plural: *"When am I?"* is asked of **a person**, so a region's eras
11collect **every valid answer** a local could give — overlapping calendars at the
12same place and time are expected, not an error.
13
14**Read these first** — they are the source of truth, defer to them over this skill:
15- `src/data/calendars/SCHEMA.md` — the human-readable field docs.
16- `scripts/validate-data.mts` — the authoritative machine-checkable schema.
17- `src/utils/calendars.ts` — which calendar strings are **convertible** (have a converter).
18- An existing file as a template, e.g. `src/data/calendars/iran.json` (two eras,
19 two converters) or `src/data/calendars/massachusett.json` (descriptive-only +
20 an `anchorEvents` "winters since" reckoning).
21
22## The one rule that overrides everything: never invent
23
24This dataset is only as trustworthy as its sources. **Do not invent** events,
25moon names, era boundaries, dates, or polygons. Every era and every anchor event
26must trace to a real, citable source (Wikipedia is acceptable as the project's
27*acceptance* gate). If you cannot source a claim, leave it out and say so. When a
28fact is uncertain or contested, prefer the conservative version and note it in
29the `description`. If you find yourself guessing a date or a boundary, stop.
30
31## Workflow
32
33### 1. Gather inputs
34Ask the user (or confirm) the **place** and the **people/polity** — e.g. "the
35Mughal Empire", "Coast Salish around Puget Sound", "Joseon Korea". The answer is
36about *whose* reckoning it is, so be specific: "Algonquian" is a language family,
37not one calendar; pick the actual nation.
38
39### 2. Research the calendar system(s) — with sources
40For that place + people, determine:
41- Which calendar system(s) were used, and over **which date ranges** (era
42 boundaries). Multiple eras are normal (e.g. a switch from a lunar to a solar
43 civil calendar, or a Julian→Gregorian cutover).
44- **Whose** answer each is (`usedBy`), e.g. "court and civil administration",
45 "Orthodox church", a specific people.
46- Real, dateable sources for each. Collect the URLs as you go.
47
48Use WebSearch/WebFetch to research; cite what you actually read.
49
50### 3. Choose the calendar string (convertible vs descriptive-only)
51This is **two independent gates** (see plan.md, Q3):
52- **Acceptance** — a sourced wiki page is enough to include the calendar at all.
53- **Convertibility** — whether a deterministic epoch+rule yields a numeric local
54 year. This is decided by `src/utils/calendars.ts`:
55 - **Convertible** strings hit a converter there: `Gregorian`, `Julian`, and the
56 Temporal-backed `Islamic`, `Hebrew`, `Persian`, `Indian`/`Saka`, `Buddhist`,
c571572f 2026-06-21 Pavel Safronov57 `Japanese`, `Ethiopic`, plus the hand-rolled `Chinese sexagenary cycle`,
12bc9942 2026-06-23 Pavel Safronov58 `Maya Long Count`, `French Republican calendar` (year only, via a
c571572f 2026-06-21 Pavel Safronov59 sourced lookup table — its year began at the Paris equinox, an
12bc9942 2026-06-23 Pavel Safronov60 observation, not a fixed rule), and the simple year-offset counts
61 `Dangi`/`Juche`, `ab urbe condita` (AUC), and `Seleucid era`.
4a2e1dbe 2026-06-21 Pavel Safronov62 Match an existing string **exactly** (the lookup is case/space-insensitive).
63 - **Descriptive-only** — a calendar with no continuous numbered year (e.g. an
64 observational lunar calendar). Use a clear `calendar` name; the engine shows
65 the era's name/description/sources + the Gregorian reference year and a
66 "no numbered year" note. Never mislabel a descriptive calendar as convertible.
67- If a genuinely new convertible system is needed, that's converter work in
68 `src/utils/calendars.ts` (a Temporal `calendarId` if Intl supports it, else
69 hand-rolled). **Caveat:** the Temporal `chinese` calendar is broken in
70 `@js-temporal/polyfill@0.5.1` (throws on every date) — that's why China uses a
71 hand-rolled `Chinese sexagenary cycle` converter instead. Verify any new
72 Temporal calendar actually converts before relying on it.
73
74### 4. Draft the region polygon
75GeoJSON `Polygon` (or `MultiPolygon`), coordinates as **`[lng, lat]`** (longitude
76first — easy to get backwards), outer ring **closed** (first position repeated as
77last), ≥4 positions. Keep it a reasonable approximation of the territory; the
78validator checks ranges (lng −180..180, lat −90..90) and closure, not accuracy —
79that's the reviewer's job against the screenshot. geojson.io is handy for drafting.
80
81### 5. Add `anchorEvents` for descriptive-only calendars (optional)
82For a calendar with no numbered year, an `anchorEvents` entry lets a local place
83you in time as "about N winters since &lt;event&gt;". Each event needs a `name`, a
84proleptic-Gregorian `date`, and **at least one source** — these must be real,
85documented events (e.g. the 1616–1619 New England epidemic), never invented.
86
87### 6. Write the file
88Match the shape of an existing file exactly. Dates (`start`/`end`, event `date`)
89are **proleptic Gregorian** `YYYY-MM-DD`; `null` start/end means open-ended;
90intervals are half-open `[start, end)` so a cutover date is the `end` of the old
91era and the `start` of the new one. Fill in `usedBy`, `description`, `sources`.
92
93### 7. Validate, test, screenshot — make it PR-ready
94Run, and fix anything that fails:
95```bash
96npm run validate:data # schema + geometry + dates
97npm run test # converter / engine tests still green
98npm run gen:badges # refresh the "calendar data" count badge
99npm run screenshot:calendar -- src/data/calendars/<slug>.json
100```
101The screenshot step pins a point inside the region at a representative date per
102era and captures the answer panel + shaded map into
103`screenshots/calendars/<slug>/`, so a reviewer can *see* a wrong polygon, an
104off-by-a-century era boundary, a miscategorized convertible/descriptive call, or
105a broken conversion. Attach these to the PR.
106
107### 8. If you added or changed a converter
108Add unit tests in `src/utils/calendars.test.ts` with a known date↔year pair, and
109update the convertible-calendars list in `README.md` and this skill's step 3.
110
111## Definition of done
112- `npm run validate:data` and `npm run test` pass.
113- Every era and anchor event is sourced; nothing is invented.
114- Convertible-vs-descriptive is correct and the conversion looks right in the
115 screenshot.
116- README's convertible-calendar list and the badge count are current.
117- **Do not commit.** Per repo policy, hand the file + screenshots to the human to
118 review against the sources, and let them commit.