Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
fd65379
fix(points): refuse event-code check-in for banned hackers
aamoghS Oct 15, 2026
a746a68
fix(announcements): stop counting in-app posts as emailed
aamoghS Oct 15, 2026
1c42309
fix(submit): encode the hackathon id in submit page links
aamoghS Oct 15, 2026
4bec229
fix(registration): keep sensitive answers out of the saved draft
aamoghS Oct 15, 2026
1c867da
feat(points): refuse overlapping and back-to-back event check-ins
aamoghS Oct 15, 2026
b195729
feat(points): record refused check-ins as flags for organisers
aamoghS Oct 15, 2026
a79cd7f
feat(judging): show check-in flags to organisers in the projects list
aamoghS Oct 15, 2026
4e752c0
feat(judging): keep teams pulled from prizes out of results
aamoghS Oct 15, 2026
d0fb5f2
feat(judging): mark flagged teams on the judge desk
aamoghS Oct 15, 2026
d49c74d
feat(judging): make the presentation deadline a hard end for judges
aamoghS Oct 15, 2026
f74a033
feat(judging): give judge writes a 15 second grace past the deadline
aamoghS Oct 15, 2026
982773b
chore(test): keep agent worktrees out of root test runs
aamoghS Oct 15, 2026
7d6a163
feat(judging): grade each project once per challenge
aamoghS Oct 15, 2026
6e735a0
feat(judging): rank placings on judge-calibrated scores
aamoghS Oct 15, 2026
7d8b63c
feat(judging): keep judges to their queue and sponsors to their rooms
aamoghS Oct 16, 2026
600c788
feat(judging): count auto-submits, reopen grades, retune drift
aamoghS Oct 16, 2026
964f93e
feat(judging): assign one judge to every presentation
aamoghS Oct 15, 2026
67d6cd2
fix(judging): tighten the CP-SAT judge model and keep goals it cuts s…
aamoghS Oct 15, 2026
0997687
feat(judging): give assigned judges their presentations first
aamoghS Oct 16, 2026
51aaca1
feat(judging): show assigned judges' progress and clear stale placings
aamoghS Oct 16, 2026
b613e55
fix(judging): count scheduled presentations and linked rooms correctly
aamoghS Oct 16, 2026
5d94c82
fix(check-in): keep rule-break flags when their events are deleted
aamoghS Oct 16, 2026
e836d6b
fix(judging): refresh public results after Projects list changes
aamoghS Oct 16, 2026
c5e127a
fix(judging): auto-submit drafts first saved in the write grace window
aamoghS Oct 16, 2026
3fe3d4f
fix(judging): refresh public results after danger zone resets
aamoghS Oct 16, 2026
7e9deb2
fix(check-in): skip the event lookup when every flagged event is gone
aamoghS Oct 16, 2026
8f1e13c
fix(check-in): type the empty event list in the flag read
aamoghS Oct 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ Edition-scoped event operations. Everything hangs off `hackathon`.
- Judge roster (`judge`, `judge_assignment`): applications and approval
- Judging: room-based judging with Devpost import — `judging_*` tables (`judging.ts`). The older pool-dispatch tables (`judging_project`, `judge_vote`, `judge_queue`, `hackathon_result`) are retired and kept for past editions' results
- Points: `hackathon_event` points, staff adjustments and the point store (`points.ts`)
- Event check-in rules: nobody is checked into two events that run at the same time, or into two less than 30 minutes apart (meals are exempt). `recordEventAttendance` enforces this for pass scans, event codes and manual check-in
- Check-in rule-break flags: each refused attempt is recorded (`hackathon_check_in_flag`, `services/check-in-flags.ts`) and shown in judging on the hacker's team, in full to organisers and as a bare marker to judges. Organisers decide whether to pull the team from prizes (`judging_entry.prize_ineligible_at`). A flag outlives the events it names (deleting one clears its id and the organiser view shows "A deleted event"). Hackers never see flags, and they stay out of public and cached payloads
- Announcements and acceptance waves

Hackathon participation is **open to non-members**. Membership is not a registration requirement.
Expand Down
2 changes: 1 addition & 1 deletion docs/operations/environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Without `DATABASE_URL`, `db` is null, sessions fall back to JWT, and tRPC proced

| Variable | Default / notes |
| --- | --- |
| `JUDGING_CPSAT_PYTHON` | A Python with OR-Tools (`python3` or a path). Set, the schedule section can run `packages/api/scripts/judging-schedule/cpsat.py` on the server (`judging.schedule.solveCpsat`). Unset means CP-SAT is download, run on a laptop, upload |
| `JUDGING_CPSAT_PYTHON` | A Python with OR-Tools (`python3` or a path). Set, the schedule section can run `packages/api/scripts/judging-schedule/cpsat.py` on the server (`judging.schedule.solveCpsat`), and `judging.schedule.assignJudges` uses it to pick judges. Unset means CP-SAT is download, run on a laptop, upload, and the app assigns judges itself |
| `JUDGING_CPSAT_SCRIPT` | Path to `cpsat.py`. Default: found by walking up from the working directory |

## Security / proxy
Expand Down
1 change: 1 addition & 0 deletions docs/operations/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Config: `packages/api/vitest.config.ts`. Includes `src/**/*.test.ts` and `src/.i
| Hackathon flow | `hackathon-flow.test.ts`, `hackathon-admin-edge.test.ts`, `hackathon-interest.test.ts` |
| Payments | `stripe-payments.test.ts` |
| QR / check-in | `qr-checkin.test.ts` |
| Check-in rule-break flags | `services/check-in-flags.test.ts`, `.internal-tests/check-in-flags-*.test.ts` |
| Security / sanitizer / rate limit | `security.test.ts`, `resilience.test.ts` |
| Judges / participants / initiatives / bootcamp / announcements | matching `*-edge.test.ts` / `bootcamp.test.ts` / `announcements.test.ts` |
| Portal context | `services/portal-context.test.ts`, `routers/user/portal-context.test.ts` |
Expand Down
8 changes: 7 additions & 1 deletion docs/packages/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,13 @@ Batch status updates allow up to **2500** ids. The global array cap in `scrubMar

**Admin** (`admin.ts`): `list`, `create` (add by email), `setActive` (approve or suspend), `remove` (super admin).

Judging itself is the `judging` namespace; its shared helpers are in `services/judging/` (`room-link`, `scope`, `scoring`, `config`). `hackathon.getResults` returns published placings from both the retired `hackathon_result` table and `judging_placement`, in one shape.
Judging itself is the `judging` namespace; its shared helpers are in `services/judging/` (`room-link`, `scope`, `scoring`, `config`). `hackathon.getResults` returns published placings from both the retired `hackathon_result` table and `judging_placement`, in one shape. It leaves out entries pulled from judging (`deleted_at`) or from prizes (`prize_ineligible_at`, set by `judging.admin.setPrizeEligibility`). Check-in rule-break flags (`services/check-in-flags.ts`) reach organisers through `judging.admin.listEntries` and `judging.results.list`, and judges through `judging.desk` as a bare `flagged` boolean; no hacker-facing, public or cached procedure returns them.

Placings rank on scores adjusted for judge bias (`services/judging/calibration.ts`): each evaluation is calibrated within its root challenge for its judge's strictness, spread and drift, on the assumption that `judging.desk.nextProject` (`services/judging/queue.ts`) hands every judge a random sample of projects. `judging_placement.raw_score` keeps the plain mean; only `judging.results.list` (organisers) returns it and the per-judge calibration, and `judging.desk` stays on raw means. An evaluation counts when it holds a rating for every rating item (`scoring.hasEveryRating`, and `scoring-sql.holdsEveryRating` where the database counts), whether or not a written response is missing, so a draft submitted at the hard end still places its project. Organiser counts, the board and hacker itinerary status, hacker feedback, and the desk's scores, judged count and shortlist all use that rule. `judging.results.list` keeps the calibration for 60 seconds per edition, keyed on the edition's evaluation count and latest save and on its ranked entries, while `judging.results.compute` always calibrates fresh. `judging.admin.reopenGrade` deletes one evaluation and the drafts for its project and challenge so another judge can grade it, and clears the edition's unpublished placings, so publishing needs a fresh compute; it is refused while results are published.

At an untimed challenge that random sample is enforced (`services/judging/queue-store.ts`): `judging.desk.nextProject` offers only the first `QUEUE_WINDOW` (3) open projects of the judge's own queue and takes a `skip` list for a team away from its table, and a judge's first `startGrading`, `saveDraft` or `submit` on a project outside that window is refused. `judging.desk.startGrading` holds a project from the moment it is opened, with an empty draft. A table judge grades a sponsor's challenge only from a seat in a room that serves it (`scope.isSponsorChallenge`); `judging.desk.context` lists only the challenges they may pick.

A scheduled presentation can have one assigned judge (`judging_appointment.assigned_judge_id`, set by `judging.schedule`; `services/judging/schedule/judges.ts` decides who may be assigned it). The desk never writes it and never tells a judge which other judge is assigned to, holds or graded a project. From the presentation's start until `TAKEOVER_AFTER_MS` (5 minutes) later only the assigned judge may open it (`services/judging/timing.ts`), and other judges see it as `reserved` with the time it opens. After that any judge who may grade it there can take it over, unless the assigned judge has started: their draft holds it (`grading-hold.ts`). Every claim checks this under the grading lock. `judging.desk.nextProject` offers the judge's own running assignments first; the queue window does not apply to scheduled challenges. `judging.desk.itinerary` lists the caller's assigned presentations that have not ended, soonest first, with the room and whether they are seated there. `judging.desk.releaseGrading` deletes the caller's own draft while it is still the empty one `startGrading` made, so a skipped or accidentally opened project is free again. `judging.schedule.get` gives organisers each started assignment's `judgeProgress` (grading, graded, taken over, not started).

## Club procedures (selected)

Expand Down
2 changes: 1 addition & 1 deletion docs/packages/db.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Files in `src/schemas/`, re-exported from `schemas/index.ts`. `drizzle.config.ts
| `auth.ts` | `user`, `account`, `session`, `verificationToken` |
| `members.ts` | `user_profile`, `member`, `membership_history` |
| `admins.ts` | `admin` |
| `hackathons.ts` | `hackathon`, `hackathon_team`, `hackathon_participant`, `hackathon_project`, `hackathon_interest`, `hackathon_event`, `hackathon_event_attendee`, `hackathon_announcement`, `hackathon_announcement_recipient` |
| `hackathons.ts` | `hackathon`, `hackathon_team`, `hackathon_participant`, `hackathon_project`, `hackathon_interest`, `hackathon_event`, `hackathon_event_attendee`, `hackathon_check_in_flag`, `hackathon_announcement`, `hackathon_announcement_recipient` |
| `judge.ts` | `judge`, `judge_assignment` (live roster); `judging_project`, `judge_vote`, `judge_queue`, `hackathon_result` (retired, kept for past editions) |
| `judging.ts` | `judging_*`: config, entries and members, challenges, buildings, rooms and room links, judges, guest sessions, presence, schedule and appointments, rubric, evaluations, deliberation, placements |
| `points.ts` | `hackathon_point_adjustment`, `hackathon_store_item`, `hackathon_store_purchase` |
Expand Down
Loading
Loading