feat: the in-world calendar (#126) #1214

Merged
claude-bot merged 27 commits from feat/126-calendar into main 2026-10-17 15:37:54 +00:00
Collaborator

Fixes #126: the in-world calendar. Design: docs/design/in-world-calendar.md (branch design/126-in-world-calendar). The owner's answers are Q183 to Q187: (a) for the first four, and (b) for Q187, named ages.

Engine

  • One date arithmetic in Python (app/services/world_calendar.py) and JS (src/calendar/engine.js), held together by one shared set of 1,128 test cases (src/calendar/cases.json). The expected results come from brute force, datetime and hand-written strings, never from the engine (scripts/calendar_cases.py --check).
  • Months, festival and leap days carry stable ids and can sit outside the week. Leap rules follow the Gregorian pattern, and there are moons.
  • Four generic presets, with no setting names (Q183 a).

Server

  • Migration a126ca1e0d01 (now revising a1181f11e5a1): world_calendars, and the sessions.world_* columns.
  • Calendar CRUD with the C6 check. Changes that would break a stored date are refused with the list of what uses it. Others remap every stored date by id in the same transaction.
  • Copy a calendar from another campaign, or save and load it as a file.
  • Session dates: a start, plus a span in hours or days with "ran past midnight" (Q184 a), and a default start.
  • Timeline world_date and named ages; the campaign's "today".
  • Export schema version 21.
  • The approved summary's Discord post gains "In the story" (Q186 a). This is additive, with no contract bump.

Screens

  • A date picker: an ARIA grid, festival cells, before-era years, precision.
  • Settings → Calendar: presets, a full editor, a live preview, save with the check.
  • On the session page:
    • "In the story…" in Manage, plus the header line;
    • one quiet row in the review (Q185 a).
  • The Sessions list and campaign home lines.
  • Wiki timeline dates and named ages.
  • The Storyline's "As we played" / "In the world" switch, with "N days later".

Tests

  • Engine: 1,176 server and 1,129 browser checks.
  • Backend: 2,492 in the calendar-touched areas.
  • Bot: 1,225.
  • New journey J9: passes on desktop, phone and keyboard, with J5, J6 and J8 also green.
  • The 4.6.0 integration rehearsal: 10,333 backend tests and 187 journeys passed.

The merge with main puts Settings → Files and Calendar side by side; those resolutions are taken from the rehearsal. Squash on merge: several builder commits lack the co-author line.

🤖 Generated with Claude Code

Fixes #126: the in-world calendar. Design: `docs/design/in-world-calendar.md` (branch `design/126-in-world-calendar`). The owner's answers are Q183 to Q187: (a) for the first four, and (b) for Q187, named ages. **Engine** - One date arithmetic in Python (`app/services/world_calendar.py`) and JS (`src/calendar/engine.js`), held together by one shared set of 1,128 test cases (`src/calendar/cases.json`). The expected results come from brute force, `datetime` and hand-written strings, never from the engine (`scripts/calendar_cases.py --check`). - Months, festival and leap days carry stable ids and can sit outside the week. Leap rules follow the Gregorian pattern, and there are moons. - Four generic presets, with no setting names (Q183 a). **Server** - Migration `a126ca1e0d01` (now revising `a1181f11e5a1`): `world_calendars`, and the `sessions.world_*` columns. - Calendar CRUD with the C6 check. Changes that would break a stored date are refused with the list of what uses it. Others remap every stored date by id in the same transaction. - Copy a calendar from another campaign, or save and load it as a file. - Session dates: a start, plus a span in hours or days with "ran past midnight" (Q184 a), and a default start. - Timeline `world_date` and named ages; the campaign's "today". - Export schema version **21**. - The approved summary's Discord post gains "In the story" (Q186 a). This is additive, with no contract bump. **Screens** - A date picker: an ARIA grid, festival cells, before-era years, precision. - Settings → Calendar: presets, a full editor, a live preview, save with the check. - On the session page: - "In the story…" in Manage, plus the header line; - one quiet row in the review (Q185 a). - The Sessions list and campaign home lines. - Wiki timeline dates and named ages. - The Storyline's "As we played" / "In the world" switch, with "N days later". **Tests** - Engine: 1,176 server and 1,129 browser checks. - Backend: 2,492 in the calendar-touched areas. - Bot: 1,225. - New journey J9: passes on desktop, phone and keyboard, with J5, J6 and J8 also green. - The 4.6.0 integration rehearsal: 10,333 backend tests and 187 journeys passed. The merge with main puts Settings → Files and Calendar side by side; those resolutions are taken from the rehearsal. **Squash on merge:** several builder commits lack the co-author line. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entries carry an id; check_change derives the remap from ids and remap_dates
rewrites stored indexes. Festival and leap days can sit outside the week.
scripts/calendar_cases.py builds cases.json from brute-force enumeration.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Merge main into feat/126-calendar; its migration follows a1181f11e5a1; Files and Calendar both in Settings
All checks were successful
CI / Does this change touch the recording path? (pull_request) Successful in 21s
CI / Synthetic session harness (no GPU, no LLM) (pull_request) Has been skipped
CI / Which journeys does this change need? (pull_request) Successful in 28s
CI / Bot/backend version sync (pull_request) Successful in 49s
CI / Docker image build (pull_request) Successful in 57s
CI / Backend lint (ruff) (pull_request) Successful in 58s
CI / Feedback site tests (pull_request) Successful in 1m29s
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 1m30s
CI / Bot tests and audit (pull_request) Successful in 2m36s
CI / Frontend (shard 2/2) (pull_request) Successful in 8m42s
CI / Frontend (shard 1/2) (pull_request) Successful in 9m57s
CI / End-to-end journeys (phone) (pull_request) Successful in 21m12s
CI / End-to-end journeys (keyboard) (pull_request) Successful in 22m51s
CI / End-to-end journeys (desktop) (pull_request) Successful in 22m54s
CI / Backend migration, tests, and audit (pull_request) Successful in 34m1s
d47c929de3
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude-bot scheduled this pull request to auto merge when all checks succeed 2026-10-17 15:03:48 +00:00
Sign in to join this conversation.
No description provided.