Hackathon day at HS Hacks and learned a lot

Apr 18, 2026 · Day 44

Progress Delta:

  • Completed: We shipped a working Momentum build at HS Hacks, validated the end-to-end flow in live conditions, and kept continuity with runtime snapshot plus IBX refresh on /api/todos, /api/todos?today=2026-04-18, /api/thoughts, and thought-level todo routes.
  • Unresolved: Core Ryva second-run pressure is still open, follow-up-only block is still open, and repo-run backlog (Kernel, Moss, Notte, Trigger.dev, Signadot, Inngest) still needs explicit closure.
  • New risks: Duplicate IBX task states can overstate progress, and hackathon momentum can decay if not converted into measurable second-run outcomes.

Diary: Today was a real shipping day. We went to HS Hacks, built Momentum under time pressure, and learned where the product is strong versus where it still needs engineering hardening.

Screenshot 2026-04-18

Project links:

Ryva run addendum:

Screenshot 2026-04-18

Most important Ryva findings:

  • Critical repo hygiene: remove or ignore .DS_Store from commit 4fcadee, then verify .gitignore:1-3 blocks recurrence.
  • High-confidence deployment blocker: validate hs-ai/src/app/api/agora/token/route.ts with AGORA_APP_ID and AGORA_APP_CERTIFICATE set.
  • Coordination gap: publish one async top-level update referencing PR #1 and commit 4fcadee with only immediate follow-ups.
  • Repo scope decision: confirm whether hs-ai/.agents/skills/ai-sdk/* belongs in this app repo or should be isolated.

Screenshot 2026-04-18

The best part was validating the architecture with real users instead of private assumptions. The realtime loop held up: client CV inference, room updates, signal polling, leaderboard persistence, and session tracking all worked together without major breakage.

Technical notes from today:

  1. Input normalization and bounded writes carried a lot of reliability.
  • normalizeRoomId, normalizeDeviceId, normalizeUsername, normalizeDayKey reduced malformed state before DB writes.
  • Hard caps (MAX_REPS, landmark limits, signal limits) made payload behavior predictable under noisy webcam streams.
  1. Monotonic rep updates prevented visible regressions.
  • Using Math.max for session and leaderboard counters avoided scoreboard drops when frame detection temporarily undercounted reps.
  • This mattered in live demo conditions where tracking confidence fluctuated by angle and lighting.
  1. Stale-state pruning kept realtime rooms healthy.
  • pruneStaleDevices and pruneStaleSignals prevented ghost participants and old signaling artifacts from polluting active sessions.
  • TTL-based cleanup improved room continuity and reduced confusing stale peers.
  1. Analytics layer is becoming decision-grade.
  • Calendar insights aggregate daily sessions, streaks, rep totals, and calorie estimates from normalized day keys.
  • Filtering by meaningful sessions avoids counting room-presence noise as workouts.

Code slice from today:

const STALE_MS = 12_000;
const SIGNAL_TTL_MS = 30_000;
const MAX_REPS = 100_000;
const CALORIES_PER_REP = 0.42;

function normalizeRoomId(roomId: string): string {
  return roomId.trim().slice(0, ROOM_ID_MAX);
}

function normalizeDeviceId(deviceId: string): string {
  return deviceId.trim().slice(0, DEVICE_ID_MAX);
}

function caloriesFromReps(reps: number): number {
  return Number((Math.max(0, reps) * CALORIES_PER_REP).toFixed(1));
}

export const upsertDevice = mutation({
  args: {
    roomId: v.string(),
    deviceId: v.string(),
    userId: v.union(v.string(), v.null()),
    username: v.string(),
    reps: v.number(),
    poseLandmarks: v.array(wireLandmarkValidator),
    handLandmarks: v.array(v.array(wireLandmarkValidator)),
  },
  handler: async (ctx, args) => {
    const roomId = normalizeRoomId(args.roomId);
    const deviceId = normalizeDeviceId(args.deviceId);
    if (!roomId || !deviceId) throw new ConvexError("Invalid identifiers.");

    // sanitize payloads, keep reps monotonic, upsert room state,
    // update leaderboard, and prune stale rows
  },
});

Security and hardening read:

  • Good: strict validators, normalization, explicit clamping, stale cleanup, and bounded list sizes.
  • Risk: abuse control is still thin for high-frequency realtime routes.
  • Next hardening pass should include rate limiting, full API auth audit, payload size ceilings, and better observability around fallback paths.

Bottom line from this hackathon run: the product loop is real, and the technical foundation is good enough to compound if we keep execution tied to measurable second-run outcomes.