Skip to content

calv4 fix: the mismatch banner printed a remedy nobody could follow - #84

Merged
keyxmakerx merged 1 commit into
mainfrom
claude/coordinator-handoff-stage-3-3d3s4w
Aug 11, 2026
Merged

calv4 fix: the mismatch banner printed a remedy nobody could follow#84
keyxmakerx merged 1 commit into
mainfrom
claude/coordinator-handoff-stage-3-3d3s4w

Conversation

@keyxmakerx

Copy link
Copy Markdown
Owner

The module half of item 6 in
keyxmakerx/Chronicle#589
("calv4 fixes: the six confirmed defects from the operator's first look"). The
Chronicle half of this one is a booking, because the thing this banner asked for
genuinely cannot be done over there yet.

The defect

All three places this module reports a calendar-structure mismatch — the
permanent ui.notifications.warn from _pauseCalendarSyncForMismatch, and the
dashboard's paused and incompatible Calendar-tab banners — told the
operator to

"Import or author the matching calendar in Chronicle."

Neither half is reachable, and both were measured against Chronicle's source
rather than guessed:

  • Import. POST /api/v1/campaigns/:cid/calendar (api_handler.go
    CreateCalendar) answers a structured 409 calendar_already_exists whenever
    GetCalendar(campaignID) returns anything, and that repo query is
    … WHERE campaign_id = ? ORDER BY is_default DESC, sort_order ASC LIMIT 1
    any calendar. A campaign showing this banner has one by construction: the
    mismatch was computed by comparing against it. The import door is closed 100%
    of the time this advice is on screen.
  • Author. calendarService.CreateCalendar sets IsDefault: isFirst, so only
    the first calendar a campaign ever gets is the default; this module is served
    the default by that same ordering; and Chronicle's SetDefaultCalendar exists
    on the service interface with no route, no handler and no control on any
    page
    . An authored calendar therefore never reaches the wire, and there is
    nothing the operator can click to change that.

The fix

The remedy is an edit, and that one is genuinely one page away: make the two
structures agree by editing a calendar that already exists. Chronicle's Calendar
Settings owns months and weekdays — exactly the facts this guard compares — and
Calendaria / Simple Calendar own the Foundry side. All three prints now say so,
and say the same thing as each other.

What is still impossible is booked, not printed

Pointing this module at a different Chronicle calendar needs Chronicle to wire
SetDefaultCalendar to a route and a control, and/or to honour a ?calId= on
the syncapi reads. That is recorded in CLAUDE.mdBlocked on Chronicle,
with the source facts to re-verify it, and mirrored in Chronicle's .ai/todo.md
and .ai/status.md.

Advice that cannot be followed is worse than no advice: the operator spends the
session believing the fix is theirs to make.

The guard

tools/test-calendar-mismatch-remedy.mjs reads all three strings from where they
ship — the toast by invoking the pause path against a stub, the banners out of
sync-dashboard.hbs — and holds each to the same verdict:

  1. never recommend an import or a new calendar (each pattern paired with the
    Chronicle source fact that closes it, so a future reader can re-verify rather
    than trust the file);
  2. always name a reachable action;
  3. do not lose the three facts the old toast got right — sync is paused, a reload
    clears it, journals/characters/maps still sync.

It also asserts the template still carries exactly two mismatch hints, so a third
banner cannot be added below this standard.

RED   2 of 3 subtests fail — the pause toast and both banner hints
GREEN 3/3

Verification

  • node --test tools/test-calendar-mismatch-remedy.mjs — 3 pass / 0 fail.
  • node --test tools/test-*.mjs (the whole suite, which is what CI runs) —
    782 pass / 0 fail, 0 skipped.
  • node tools/check-package-descriptor.mjs — OK, 0 warnings.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Aa645128uaFxbQyvabMizq


Generated by Claude Code

All three places this module reports a calendar-structure mismatch — the
permanent ui.notifications.warn from _pauseCalendarSyncForMismatch, and the
dashboard's paused and incompatible banners — told the operator to

  "Import or author the matching calendar in Chronicle."

NEITHER HALF IS REACHABLE, measured against Chronicle's source rather than
guessed:

  IMPORT. POST /api/v1/campaigns/:cid/calendar (api_handler.go CreateCalendar)
  answers a structured 409 `calendar_already_exists` whenever
  GetCalendar(campaignID) returns anything, and that repo query is
  `... WHERE campaign_id = ? ORDER BY is_default DESC, sort_order ASC LIMIT 1`
  — ANY calendar. A campaign showing this banner HAS one by construction: the
  mismatch was computed by comparing against it. The import door is closed 100%
  of the time this advice is on screen.

  AUTHOR. calendarService.CreateCalendar sets `IsDefault: isFirst`, so only the
  first calendar a campaign ever gets is the default; this module is served the
  default by that same ordering; and Chronicle's SetDefaultCalendar exists on
  the service interface with NO route, NO handler and NO control on any page. An
  authored calendar therefore never reaches the wire, and there is nothing the
  operator can click to change that.

THE REMEDY IS AN EDIT, and that one is genuinely one page away: make the two
structures agree by editing a calendar that already exists. Chronicle's Calendar
Settings owns months and weekdays — exactly the facts this guard compares — and
Calendaria / Simple Calendar own the Foundry side. All three prints now say so,
and say the same thing as each other.

WHAT IS STILL IMPOSSIBLE IS BOOKED, NOT PRINTED. "Point the module at a
different Chronicle calendar" needs Chronicle to wire SetDefaultCalendar to a
route and a control, and/or honour a ?calId= on the syncapi reads. That is
recorded in CLAUDE.md → Blocked on Chronicle with the source facts to re-verify
it, and in Chronicle's own .ai/todo.md and .ai/status.md. Advice that cannot be
followed is worse than no advice: the operator spends the session believing the
fix is theirs to make.

tools/test-calendar-mismatch-remedy.mjs reads all three strings from where they
ship — the toast by invoking the pause path against a stub, the banners out of
sync-dashboard.hbs — and holds each to the same verdict: never recommend an
import or a new calendar, always name a reachable action, and do not lose the
three facts the old toast got right (sync is paused, a reload clears it,
journals/characters/maps still sync).

  RED  (before): 2 of 3 subtests fail — the toast and both banner hints
  GREEN (after): 3/3, and the full module suite is 782 pass / 0 fail

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Aa645128uaFxbQyvabMizq
@keyxmakerx
keyxmakerx merged commit c7dd3b2 into main Aug 11, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants