What it will not do
Written before you need it rather than after. Some of these are gaps we chose, some are gaps we have not closed, and the difference is marked.
Real gaps
The fold needs a complete break that divides evenly into rooms. Partial breaks, byes, and partial double-octofinals produce no projection at all — the page shows the announced break and the bracket stays empty rather than guessing.
This is the biggest limitation here. If your tournament breaks 24 teams into a partial double-octofinal, the fold view works and the bracket projection does not. Everything else on the page is unaffected.
The hosted version of tester tracking is the least exercised part of this toolkit. It works, and it is the right answer if a whole adjudication core want one shared view instead of one per laptop. But it has not been run against a live tournament as recently as the rest, and it runs on Netlify functions, which is a heavier setup than anything else here.
Start with the local version. If you want the shared one, try it a week before your tournament, not during it.
A category called “Novice” costs you the word “novice”. Break category names are banned from feedback summaries, because “the novice semis” places a debate as surely as “round five”. Names that are everyday English — Open, Main — get an exemption; distinctive ones do not. So at a tournament with a Novice category, a summary cannot say “a novice judge”.
That is the anonymity trade being made deliberately, and it is the kind of thing worth knowing before it puzzles you.
Things that need something installed
- Judge feedback needs the
claudecommand-line tool, because that is what writes the summaries. Nothing else in the toolkit uses it. - Publishing needs a hosting account — Cloudflare by default, free. You can skip publishing entirely and open the built pages locally.
- Windows needs WSL. The scripts are shell scripts and the paths are POSIX. This is fixable and nobody has needed it yet.
Things it deliberately does not do
- It does not generate draws, allocate judges, or touch a ballot. Tabbycat does all of that well. Anything that writes to a tab is out of scope by construction, not by omission.
- The feedback tool does not report an agreement rate, or how many people wrote in. Both are scores by another name, and the whole point is that there are no scores.
- There is no way to look up another judge's feedback. No index, no search, no listing.
- The feedback tool is not automated and should not be. A person reading the summaries before they go out is a feature.
- Tester tracking does not write your tester list back to Tabbycat. Partly because nothing here writes to a tab, and partly because “who we are using as a tester this weekend” is not a fact about the tournament.
Scale
Tested to roughly a hundred judges, fifty teams and a couple of thousand feedback submissions — a large intervarsity. A pull takes well under a minute.
Something much larger would probably work and has not been tried. The one part that scales with judges rather than with data is writing the feedback summaries: one model call each, several at a time, so a hundred judges is minutes rather than seconds. If you run something on that scale and it struggles, say so.
Why a partial break is genuinely hard, not just unimplemented
The fold's projection rests on one property: with P rooms in a break round, room i meets room P+1−i, and that tree is fixed at the break. It is what lets the page draw a bracket nobody has been drawn into yet.
A partial break has no such tree. Some teams enter at the double-octofinals and some skip to the octofinals, and which is which depends on the break size, the room count, and the tournament's own rule about who gets the bye — a rule that is not in Tabbycat's API because it is a decision, not a setting.
So seedRooms() returns null unless the announced break is
complete and divides evenly into rooms, and every view that would draw a
projection renders its empty state instead. Guessing would produce a bracket
that looks authoritative and is wrong, which is worse than an empty one — the
same reasoning as making failures
loud.
What would fix it: read the real elimination draw once tab publishes it
(which already works) and simply never project for a partial break. That is
most of the value, and it is a small change to core.js if
somebody wants it.
Next year
Tabbycat changes, and a version bump could move a field this toolkit reads. The demo cannot catch that, because the demo is a fake Tabbycat that will not have changed.
What will happen is a clear failure rather than a quiet wrong answer: the allowlist rejects an undeclared field, the gates refuse to publish, and pulls raise instead of returning empty. That is by design — see failures are made loud on purpose. But budget an hour to run the demo and one dry build before your tournament rather than on the morning of it.