Skip to content

Clojure math.repness: priority-metric meta detection treats 0 as truthy, assigning META_PRIORITY^2 to every comment #2571

@jucor

Description

@jucor

Clojure math.repness: priority-metric meta detection treats 0 as truthy, assigning META_PRIORITY^2 to every comment

Summary

priority-metric in math/src/polismath/math/conversation.clj is intended to
distinguish "meta" comments (which get a constant high priority,
META_PRIORITY^2 = 49) from regular comments (which get
(importance * decay-factor)^2). Due to a Clojure truthiness quirk, the meta
branch fires for every comment, so every tid ends up with priority 49.0.

The math pipeline still runs, but comment-priorities is effectively constant
across all comments, defeating the priority-weighted sampler that picks
which comments to surface to participants.

Affected code

math/src/polismath/math/conversation.clj:321-330 (approx.):

(defn priority-metric
  [is-meta A P S E]
  (matrix/pow
    (if is-meta
      meta-priority
      (* (importance-metric A P S E)
         (+ 1 (* 8 (matrix/pow 2 (/ S -5))))))
    2))

And the caller, around conversation.clj:325, which produces is-meta:

(get meta-tids tid 0)   ; or similar — returns 0 when tid is not in meta-tids

Mechanism

  1. meta-tids is a set (or map) of meta tids.
  2. (get meta-tids tid 0) returns 0 for tids not in meta-tids (the default).
  3. In Clojure, only nil and false are falsy0 is truthy.
  4. So (if is-meta meta-priority ...) selects the meta-priority branch
    regardless of whether the tid is actually meta.
  5. Result: every comment's priority is META_PRIORITY^2 = 49.0.

Empirical evidence

Prodclone check on two conversations (2026-06-11):

Conversation Meta tids Non-meta tids Distinct priorities in blob
vw 0 all 1 (all 49.0)
biodiversity 15 301 1 (all 49.0)

If the meta detection worked, we'd expect vw to have zero 49.0 priorities
(no meta tids exist) and varied non-meta values. Instead every tid is 49.0,
confirming the meta branch fires unconditionally.

Suggested fix

Use a predicate that distinguishes "absent" from "present-but-zero":

;; Option A — set membership
(contains? meta-tids tid)

;; Option B — explicit nil check (if meta-tids is a map)
(some? (get meta-tids tid))

;; Option C — explicit boolean coercion
(boolean (get meta-tids tid))

Any of these returns false (not 0) when the tid is absent, so the
(if is-meta ...) form will correctly take the non-meta branch.

Downstream impact

  • Python port (delphi/polismath/conversation/conversation.py,
    priority_metric) currently mirrors this bug for byte-for-byte parity with
    the Clojure golden snapshots. Once this Clojure bug is fixed, we will
    restore the semantically-correct Python implementation (the original logic
    is preserved as a commented block in the port; see TODO comment referencing
    this issue).
  • Re-recording Python regression snapshots after the Clojure fix will be
    required.
  • Any downstream consumer that relies on comment-priority ranking
    (e.g. probabilistic samplers in the participation flow) is currently
    operating on a constant distribution.

References

  • Clojure source: math/src/polismath/math/conversation.clj (priority-metric, ~line 321)
  • Python parity bug mirror: delphi/polismath/conversation/conversation.py::priority_metric
  • D12.6 decisions log in delphi/docs/CLJ-PARITY-FIXES-JOURNAL.md (2026-06-11)

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