Problem
"What a Vote is worth" has no deep module. src/lib/voteConfig.ts holds the canonical +2/+1/−1 weights but is a shallow constants bag, so callers re-derive aggregation inline with raw vote_type literals — and three formulas disagree:
src/pages/SetDetails.tsx:36 — net score = 2·mustGo + interested − wontGo
src/pages/EditionView/tabs/ArtistsTab/useSetFiltering.ts:21-41 — popularity = 2·mustGo + interested (no −wontGo term) and rating = mean of vote_type
src/pages/SetDetails/SetGroupVoting.tsx:45-49 — inline vote_type === 2/1/−1 counts
src/hooks/useVoteCount.ts — raw per-type counts
User-visible inconsistency: the Vote tab's popularity sort omits the Won't-Go penalty while the Set detail score badge subtracts it — a Set can rank above another it "scores" below. None of this scoring logic is unit-tested (voteConfig.test.ts covers only the config).
Proposed deepening
One pure Vote-tally module: votes in, { counts, mean, popularity, net } out. No caller ever writes vote_type === 2 again; the tally interface becomes the test surface. Requires a product decision first: which popularity formula is the intended one.
Relations
Architecture note
Explore ticket from the 2026-07-13 architecture review (candidate 1, top recommendation). Design to be settled in a grilling session before implementation. Vocabulary per /codebase-design.
Problem
"What a Vote is worth" has no deep module.
src/lib/voteConfig.tsholds the canonical+2/+1/−1weights but is a shallow constants bag, so callers re-derive aggregation inline with rawvote_typeliterals — and three formulas disagree:src/pages/SetDetails.tsx:36— net score =2·mustGo + interested − wontGosrc/pages/EditionView/tabs/ArtistsTab/useSetFiltering.ts:21-41— popularity =2·mustGo + interested(no−wontGoterm) and rating = mean ofvote_typesrc/pages/SetDetails/SetGroupVoting.tsx:45-49— inlinevote_type === 2/1/−1countssrc/hooks/useVoteCount.ts— raw per-type countsUser-visible inconsistency: the Vote tab's popularity sort omits the Won't-Go penalty while the Set detail score badge subtracts it — a Set can rank above another it "scores" below. None of this scoring logic is unit-tested (
voteConfig.test.tscovers only the config).Proposed deepening
One pure Vote-tally module: votes in,
{ counts, mean, popularity, net }out. No caller ever writesvote_type === 2again; the tally interface becomes the test surface. Requires a product decision first: which popularity formula is the intended one.Relations
getVoteValue— that fix would preserve the popularity/net discrepancy; this ticket additionally gives the aggregate formulas one owner and resolves it.useSetVoting) — that hook consumes this tally.Architecture note
Explore ticket from the 2026-07-13 architecture review (candidate 1, top recommendation). Design to be settled in a grilling session before implementation. Vocabulary per
/codebase-design.