Skip to content

Vote sign is inverted between raw storage/API and the participants-votes export (undocumented) #2554

@lgelauff

Description

@lgelauff

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):

  1. 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.
  2. Clarify intent — is the "switch" (normalizing internal storage to agree = +1) still planned, e.g. as part of the Clojure→delphi math migration?
  3. 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!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions