Skip to content

Resolve the formatDate name collision in apps/web - #934

Merged
selfcontained merged 1 commit into
mainfrom
agt_29a6e931f162/job-debt-collector-a6ba1888
Aug 11, 2026
Merged

Resolve the formatDate name collision in apps/web#934
selfcontained merged 1 commit into
mainfrom
agt_29a6e931f162/job-debt-collector-a6ba1888

Conversation

@selfcontained

Copy link
Copy Markdown
Owner

What

apps/web exported three different functions named formatDate, each with different behavior:

ModuleBehavior
components/app/activity-chart-utils.tsone-line delegation to formatShortDate
components/app/release-utils.tsone-line delegation to formatShortDateTime
components/app/jobs-helpers.tsxnull guard + invalid-date guard, then formatDateTime

Same name, three semantics. Reading formatDate(x) at a call site told you nothing about what you'd get, and the import path was the only disambiguator.

  • Deleted the two pure delegations. Their five call sites now import formatShortDate / formatShortDateTime from @/lib/format directly (activity-pane.tsx, activity-chart-utils.ts internal use, release-admin.tsx, updates-section.tsx ×2).
  • Renamed the jobs-helpers one to formatJobDateTime and left its body untouched. Its three call sites (jobs-history-tab.tsx ×2, jobs-detail-pane.tsx) and its test block were updated.

Why this is tech debt

The two deleted wrappers added an indirection layer with zero behavior of their own, and their only effect was to make a widely-used name mean three different things in one app. Net -9 lines of indirection, and formatDate no longer resolves ambiguously anywhere in the repo.

No behavior change. Every call site resolves to the exact same underlying formatter it did before.

Deliberate exclusions

  • jobs-helpers's guards were kept, not inlined. All three of its call sites do in fact pass a non-null value today (run.startedAt is typed string; run.completedAt and job.nextRun are truthiness-guarded at the call site), so the "Not scheduled" branch is unreachable from current callers. But the "Unknown" invalid-date branch is a real fallback and the fallback strings are job-domain wording — inlining them at three sites would have been strictly worse than one well-named helper. Renaming resolves the collision without touching behavior.
  • formatDateTime / formatShortDateTime / formatShortDate in @/lib/format are untouched — they are the canonical formatters and are not duplicates of each other.
  • Not swept:service-resources-format.ts and other same-shaped-but-different display helpers noted in the backlog (shortModelName, statusIcon, TabButton collisions) — those are genuinely different functions that happen to share a name, and are tracked as their own backlog item.

Validation

  • pnpm run check
  • pnpm run finalize:web
  • apps/web vitest: 776 passed / 58 files ✅
  • pnpm run test:e2e: 179 passed / 12 skipped ✅ (covers the jobs pane and the settings/updates section, which render two of the changed call sites)
  • Server vitest skipped — no backend files changed.

Queued next

Backlog index 0: the dead design-system surface policy call (ui/sheet.tsx, unused shadcn wrappers, five unused lib/glass.ts tokens) — deliberately its own run because it's a keep-or-delete policy decision, not a mechanical fix.

Three modules each exported a `formatDate` with different behavior:
activity-chart-utils.ts (formatShortDate), release-utils.ts
(formatShortDateTime), and jobs-helpers.tsx (null guard + formatDateTime).
Same name, three semantics — the kind of thing that misleads at a glance.
The first two were pure one-line delegations to @/lib/format, so they are
deleted and the five call sites now call formatShortDate/formatShortDateTime
directly. The jobs-helpers one carries real domain behavior (the "Not
scheduled" / "Unknown" fallbacks), so it is kept and renamed to
formatJobDateTime rather than inlined at three call sites.
No behavior change: every call site resolves to the same underlying
formatter it did before.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@selfcontained
selfcontained merged commit f8bbf3e into mainAug 11, 2026
1 check passed
@selfcontained
selfcontained deleted the agt_29a6e931f162/job-debt-collector-a6ba1888 branch August 11, 2026 09:09
selfcontained added a commit that referenced this pull request Aug 12, 2026
Three buckets of unreferenced design-system code have been deferred twice
(PR #807, PR #934) because they are a judgement call rather than clear-cut
dead application code. This settles the policy and applies it.
Delete what is dead weight:
- apps/web/src/components/ui/sheet.tsx (134 lines, zero importers)
- five unused tokens in lib/glass.ts (glassDivider, glassHover, glassActive,
glassBadgeBg, primaryGlow)
Keep, and say so in a comment, what is a deliberately complete vendored
API surface: DialogTrigger/DialogClose in ui/dialog.tsx and
SelectGroup/SelectLabel/SelectSeparator in ui/select.tsx.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

1 participant

@selfcontained