Skip to content

[Medium] Bug: statically-generated pages freeze deadline-derived state (stale 'closing soon' / countdowns) #47

Description

@Jose-Gael-Cruz-Lopez

Summary

All five data pages are statically generated ( in the build output), and their deadline-derived state — status (open/closing_soon/closed), daysLeft, and the marker/countdown labels — is computed from new Date() at build time. With no revalidate/ISR configured, "🔥 CLOSING SOON" flags and "N days left" countdowns freeze at the moment of the last build and drift out of sync with real time.

Location

  • web/lib/listings.ts:110-138 (build-time new Date() + deriveState/daysLeft)
  • web/lib/types-hq.ts (countdown() consumed by globe-map.tsx, deck.tsx)
  • No export const revalidate/dynamic in any web/app/*/page.tsx (build shows all pages ○ Static).

Evidence

export function loadHackathons(): Hackathon[] {
  const raw: RawListing[] = JSON.parse(fs.readFileSync(LISTINGS_PATH, "utf8"));
  const today = new Date();               // evaluated at build time on a static page
  today.setHours(0, 0, 0, 0);
  // ...
  daysLeft = Math.ceil((d.getTime() - today.getTime()) / 86_400_000);

Build route table:

┌ ○ /
├ ○ /deck
├ ○ /globe
├ ○ /hackathons
└ ○ /my        (○ = prerendered as static content)

Impact

After a deploy, a hackathon whose deadline passes (or moves within 7 days) will keep showing a stale status/countdown until the site is rebuilt. If the host is not wired to rebuild on every push, the countdowns are effectively frozen. If it is git-connected, the daily closing_soon/update_readmes bot commits to main will trigger rebuilds, bounding staleness to ~24h — but this is incidental, undocumented, and breaks the moment auto-deploy is paused. The site's core value proposition ("what's closing soon") depends on this being correct.

Recommended fix

Make the time-derived rendering explicit rather than relying on incidental rebuilds:

  • Add export const revalidate = 3600 (ISR) to the data pages so the server recomputes status/daysLeft on a schedule, or
  • Compute the countdown/status on the client from the deadline (client Date.now()), so it's always live regardless of build time, or
  • Document and guarantee the rebuild-on-push pipeline as the intended freshness mechanism.

Acceptance criteria

  • "Closing soon" flags and day counts reflect the current date without requiring a manual rebuild.
  • The freshness mechanism (ISR interval, client compute, or guaranteed rebuild) is documented.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingreliabilityReliability, error handling, resilienceseverity:mediumMedium severity

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions