DEV Community

Asuran
Asuran Subscriber

Posted on

Signed hackathon results anyone can recompute and verify

Every hackathon platform converged on the same features then stopped at the judging. The biggest one cannot weight its criteria. The ones that advertise score normalization do not document how it works. None of them lets you recompute a result, so a ranking is something you trust because the platform says so.

DOGFOOD is a 72-hour event with one product in it, a submission and judging platform that Hackathon Raptors will fork and run. We built ours around a single idea. A result should be something anyone can recompute from the raw scores and verify, with no trust in the host.

Weighted criteria, then a normalization you can defend

Judges score each criterion from 1 to 5. The organizer sets a weight per criterion. We combine them into a weighted composite that stays on the 1 to 5 scale. Then we remove each judge's leniency with an additive model (mu plus a project effect plus a judge bias) and rank by the bias-removed quality after shrinking it toward the mean by n over n plus k. On the event fixture k came out at 0.81, so a project with two reviews keeps about 71 percent of its own signal and one with five keeps about 86 percent. Coverage buys confidence, not rank. A judge who scored everyone the same contributes a bias offset and zero ranking signal, which is correct. It never divides by that judge's spread, so a zero-variance judge is not a crash.

The result is signed and you can recompute it

When results publish, the portal emits a bundle, the raw scores, the rubric and its weights, the method and its parameters, the code commit and the ranking. It is hashed over a canonical encoding and signed with an Ed25519 key the deployment generates on first boot into its own volume. A standalone verify.py recomputes the ranking from the raw scores, checks the hash and verifies the signature. Change one judge's score and it prints NOT VERIFIED. That turns "we normalized the scores" into "here is the record, recompute it yourself".

Two engines, one winner

The strongest evidence that this is real: we built the judging core as an isolated pure-Python module and wired it into the Django app separately. Fed the same raw scores and the same 0.4 0.4 0.2 weights, the two implementations independently produced the same winner, prj_16, at the same final score. Same inputs, same result, two codebases.

Honest about what it does not know

The ranking reports an uncertainty band next to every score. On this sparse fixture 39 of 40 adjacent ranks overlap, so most of the order is a statistical tie and we say so rather than faking precision. The weighted-rubric method and a Bradley-Terry pairwise pass agree on 7 of the top 10 but disagree on the very top seat, which is exactly the signal a pairwise round is for. We publish both.

It runs on a laptop with the network off

docker compose up brings the whole thing up seeded, prints the per-role tokens, then the acceptance suite passes all seven checks. The gallery is public, a closed event refuses a late submission, a judge cannot read a peer's scores over the API, the organizer exports CSV. No cloud account, no hosted database, nothing to visit. It also exports a whole event to JSON and re-imports it into a fresh instance with every project, score and value matching, so an organizer can leave as easily as they arrive.

The repo is github.com/zkasuran/dogfood-portal under MIT. The demo walks one event from create to submit to judge to publish, then runs the verifier on the real bundle and watches it reject a tampered one: youtu.be/igjISVTL2ik

AI assistance (Claude) was used to build this. The design, the maths and the verification were checked by the author. The acceptance suite plus the judging tests pass green.

Top comments (0)