Skip to content

refactor: pay down date picker branches, timezone label, and welcome step math - #4403

Merged
tyler-dane merged 2 commits into
mainfrom
claude/kind-dirac-qzzd4k
Oct 12, 2026
Merged

tyler-dane merged 2 commits into
mainfrom
claude/kind-dirac-qzzd4k

Conversation

@tyler-dane

@tyler-dane tyler-dane commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #

What and why

Nightly simplification of merges from the last seven days (#4376-#4402). Six debt items, no behavior change intended:

  • The start/end branch was written five times in DatePickers. ArrowDown, both Enter commits, Escape and Tab each re-derived "which picker am I?" from a pair of props, and the Mod+Enter case added by fix(web): restore Cmd+Enter and Esc in event time pickers #4395 duplicated the plain-Enter commit path. One record per side plus openOnly / closeOpenPickers / commitTypedDate states each rule once. Also gone: the val !== undefined guards (an input's value is always a string, and the undefined arm silently built an Invalid Date), the single-use getDateFromInput and formatDate wrappers, and the two one-line close*DatePicker closures.
  • GridTimezoneLabel carried the same button twice (feat(web): improve second timezone discoverability #4376), gated on isTraveling && travelAbbreviation !== null && timeTravelZone, where each of the three conditions implies the other two. One GridTimezoneAbbrevButton, one null check. The button forwards its ref and remaining props, because SecondaryTimezoneExitHint clones its child to anchor the tooltip on it; a wrapper that swallowed them would have left the hint with nothing to hover, focus or position against, so GridTimezoneLabel.test.tsx now pins that the cloned reference props reach the button element.
  • SecondaryTimezoneExitHint's mount effect re-set state it was already initialized with (feat(web): improve second timezone discoverability #4376). The component is keyed on the zone, so a remount is what restarts the pulse; the effect only needs the timeout.
  • WelcomeSteps lived inside WelcomeModal.tsx (one component per file), and the step clamp was inline arithmetic with as WelcomeStep casts and bare 1/3 bounds in two places (fix(web): advance welcome modal on Enter when dialog has focus #4397 touched this file). Both move to welcome-steps.ts with a unit test.
  • welcome-sequence content and templates hand-rolled the same map read (feat(email): daily welcome tip drip (day 0-4) mapped to new Resend templates #4399): "narrow the row's stepKey, else undefined", once per file. Now welcomeStepValue. In the preview loop, hasQueuedRows was redundant with isComplete (a queued row is neither sent nor skipped, so it already makes isComplete false), and two private helpers re-normalized an address their only caller had already normalized. settingsHref(page: "billing") loses a single-member union parameter.
  • SaveButton was dead code with a live test. fix(web): full-width primary Save in sidebar event form #4391 rebuilt the event form footer on Btn plus the shared c-button-primary / c-button-elevated classes, leaving SaveButton's only importer its own test file, which is why knip could not see it as unused. The component and that test go, and with them the saveButtonBg / saveButtonShadow fields on EventPalette that nothing else read. --elevated-shadow-color falls back to --color-accent-strong in CSS, which is what the footer button has used since fix(web): full-width primary Save in sidebar event form #4391.

Left alone on purpose: the TIME_PICKER_COMMIT_DRAFT_EVENT custom DOM event and its .c-time-picker class lookup (#4395) still bridge the form's save shortcut to the picker's uncommitted draft, which would need the draft lifted into the form rather than a local cleanup; prior sweeps (#4402) left it for the same reason. WELCOME_STEP_TEMPLATE_ALIAS["shortcut-list"] = "14-" reads truncated, but #4399 names that alias deliberately, so it is Resend's to rename.

Verify

Selected packages: web, backend
Checks run: test:web, type-check, lint, knip, test:a11y
Checks skipped: (none)

Failed: test:backend:fast, test:e2e
VERDICT: FAIL

Passing here: test:web 4122/4122 (at WEB_TEST_SHARDS=28; the default 6 shards OOM-kill one shard in the untouched components/ specs, which reproduces on a clean main checkout in this sandbox, same as #4385 and #4393 recorded), test:a11y 65/65, type-check, lint, knip, and test:e2e 237/238.

Both failures reproduce on unmodified main here and neither lands in a file this diff touches:

  • test:backend:fast - 597 pass, 13 fail, all GET /api/config and SSE Server specs timing out on socket binds. This container cannot listen on ::, which is also why the Mongo-backed *.db.test.ts suites (including the preview-loop ones covering the welcomeStepValue and generation-state changes) cannot run here. Verified by stashing the diff and rerunning: identical failures.
  • test:e2e - 1 failed, 237 passed: e2e/calendars/calendar-experience.spec.ts:735 toBeVisible() timeout on the hidden read-only card. refactor: drop leftover calendar skipIf and flash-jump residue #4402 listed the same spec at the same line as a sandbox failure on an untouched spec.

CI is the gate and it agrees: on the first commit of this branch (66f3e28) every required check was green, including e2e-shard (1, e2e/accessibility e2e/allday), e2e-shard (4, ... e2e/calendars ...), all six unit-leg jobs, static and macos.

Focused suites covering the diff, all green: timezone + WelcomeModal 117/117, EventForm + TimePicker 86/86, Button + SaveSection + styles + EventCard + MobileGate 86/86, non-Mongo packages/backend/src/email 40/40.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BtTkXVHELU5KLWjvJ5fNWG


Generated by Claude Code

…step math

Debt from the last week of merged work:

- DatePickers: the start/end branch was spelled out in five places (arrow
  open, both Enter commits, Escape, Tab) and the Mod+Enter case from #4395
  duplicated the plain-Enter commit. One record per side plus openOnly /
  closeOpenPickers / commitTypedDate says each rule once; drops the dead
  `val !== undefined` guards and the single-use getDateFromInput and
  formatDate wrappers.
- GridTimezoneLabel (#4376): the two abbreviation buttons were the same
  markup twice, gated on `isTraveling && travelAbbreviation !== null &&
  timeTravelZone`, where any one of the three implies the others. One
  GridTimezoneAbbrevButton, one null check. It forwards its ref and
  remaining props, since the exit-hint tooltip clones its child to anchor
  on it; a new test pins that the cloned reference props reach the button.
- SecondaryTimezoneExitHint: the mount effect re-set state it was already
  initialized with; the component is keyed on the zone, so remounting is
  what restarts the pulse.
- WelcomeModal (#4397): WelcomeSteps moved to its own file (one component
  per file), and the step clamp arithmetic with its casts and bare 1/3
  moved into welcome-steps.ts with a unit test.
- welcome-sequence: content and templates both hand-rolled the same
  "narrow stepKey, else undefined" map read; now welcomeStepValue.
  Preview loop drops hasQueuedRows, which a queued row already makes
  false through isComplete, and stops re-normalizing an address its
  caller normalized.

No behavior change intended.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BtTkXVHELU5KLWjvJ5fNWG
#4391 rebuilt the event form footer on `Btn` with the shared
`c-button-primary` / `c-button-elevated` classes, which left `SaveButton`
with no production caller: its own test file was the only importer, so
knip could not see it as unused. The component and that test go, and with
them the `saveButtonBg` / `saveButtonShadow` fields on `EventPalette`,
which nothing else read (every other consumer destructures `base`).
`--elevated-shadow-color` falls back to `--color-accent-strong` in CSS,
which is what the footer button has been using since #4391.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BtTkXVHELU5KLWjvJ5fNWG
@tyler-dane tyler-dane added the agent-automerge Agent-loop finished; merge-guard may squash-merge label Oct 12, 2026 — with Claude
@tyler-dane
tyler-dane marked this pull request as ready for review October 12, 2026 10:58
@tyler-dane
tyler-dane added this pull request to the merge queue Oct 12, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 12, 2026

Copy link
Copy Markdown
Contributor Author

Dequeued on CI_FAILURE, but no test failed. Re-queuing once, with the evidence:

The queue run's aggregate e2e gate ("Require every shard to pass") went red solely because e2e-shard (2, e2e/booking e2e/oauth e2e/auth e2e/billing) was cancelled, not failed. In that job every step reports success, including Run e2e tests; it was killed afterwards by the job's own timeout-minutes: 12 budget, having run 10:58:58 to 11:11:24 (12m26s).

That duration is the anomaly, not the code:

Run shard 2 duration result
queue branch pr-4403-c8740d78 12m26s cancelled at the job timeout
PR head a20c68a, same code, 12 min earlier 3m06s success
queue branch for #4402 3m14s success

The other three shards in the same queue run finished in about 4 minutes, so this was one stalled runner rather than a slow batch. The shard's specs (booking, oauth, auth, billing) are also untouched by this diff, which changes the all-day date pickers, the grid timezone label, the welcome modal's step dots, the welcome email step maps, and a dead button component.

Every required check is green on the PR head a20c68a: all four e2e-shard jobs, all six unit-leg jobs, static, and macos. Re-enabling auto-merge so the queue takes another pass; if the same shard times out again on a re-queue I will treat it as real and dig in rather than re-run a third time.


Generated by Claude Code

@tyler-dane
tyler-dane added this pull request to the merge queue Oct 12, 2026
Merged via the queue into main with commit ca90c52 Oct 12, 2026
27 checks passed
@tyler-dane
tyler-dane deleted the claude/kind-dirac-qzzd4k branch October 12, 2026 11:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent-automerge Agent-loop finished; merge-guard may squash-merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants