Summary. The integer sign of a vote is opposite in the raw database (and the vote API) versus the participants-votes CSV export, and the inversion isn't documented anywhere — only an 8-year-old XXX code comment. This reliably trips up anyone who reads the raw votes table or builds on the vote API. Please confirm that this is correct. I was unable to find a reason for this.
Details.
- Raw
votes / votes_latest_unique tables and the vote-submit API use agree = -1, disagree = +1, pass = 0 (matching the web client's Vote enum: Agree: -1, Disagree: 1).
- The
participants-votes export flips this to the intuitive agree = +1, disagree = -1 by negating every vote in math/src/polismath/darwin/export.clj:
(defn get-corrected-conversation-votes
[darwin & args]
(->> (apply get-conversation-votes* darwin args)
;; Flip the signs on the votes XXX (remove when we switch)
(map #(update-in % [:vote] (partial * -1)))
- That comment ("Flip the signs on the votes XXX (remove when we switch)") has been in place since at least 2018 (
0105538), so it looks like the intended "switch" never happened.
data/Export.md documents the export values (agree = 1) but never mentions that raw storage is the opposite — so a developer querying Postgres directly gets agree = -1 with no warning, and reasonably assumes data corruption or a bug in their own code.
Why it matters. Self-hosters and tool-builders (I'm one) may read the Polis Postgres directly for moderation/analytics rather than going through the CSV export. The silent sign disagreement between the two layers is a genuine footgun — It took quite a deep dive to ascertain why the voting behavior was the way it was.
Asks (in rough priority):
- Document the inversion — a sentence in
Export.md and/or the schema docs stating that raw votes.vote uses agree = -1 and the export negates it. This alone removes the trap.
- Clarify intent — is the "switch" (normalizing internal storage to
agree = +1) still planned, e.g. as part of the Clojure→delphi math migration?
- Optional migration path — if normalizing outright would break existing consumers, a per-deployment flag (default = current inverted behavior) would let operators opt into sane signs without forcing a breaking change on everyone.
Happy to open a PR for (1) at minimum, but want to verify my correct understanding first. Thanks!
Summary. The integer sign of a vote is opposite in the raw database (and the vote API) versus the
participants-votesCSV export, and the inversion isn't documented anywhere — only an 8-year-oldXXXcode comment. This reliably trips up anyone who reads the rawvotestable or builds on the vote API. Please confirm that this is correct. I was unable to find a reason for this.Details.
votes/votes_latest_uniquetables and the vote-submit API useagree = -1,disagree = +1,pass = 0(matching the web client'sVoteenum:Agree: -1, Disagree: 1).participants-votesexport flips this to the intuitiveagree = +1,disagree = -1by negating every vote inmath/src/polismath/darwin/export.clj:0105538), so it looks like the intended "switch" never happened.data/Export.mddocuments the export values (agree = 1) but never mentions that raw storage is the opposite — so a developer querying Postgres directly getsagree = -1with no warning, and reasonably assumes data corruption or a bug in their own code.Why it matters. Self-hosters and tool-builders (I'm one) may read the Polis Postgres directly for moderation/analytics rather than going through the CSV export. The silent sign disagreement between the two layers is a genuine footgun — It took quite a deep dive to ascertain why the voting behavior was the way it was.
Asks (in rough priority):
Export.mdand/or the schema docs stating that rawvotes.voteusesagree = -1and the export negates it. This alone removes the trap.agree = +1) still planned, e.g. as part of the Clojure→delphimath migration?Happy to open a PR for (1) at minimum, but want to verify my correct understanding first. Thanks!