They come from the same responses as final votes. A sitting has over a hundred, so they are flagged part_vote and only appear on request: the vote lists have an option for them, feeds, counts and search chunks leave them out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
44 lines
2.0 KiB
Python
44 lines
2.0 KiB
Python
"""Rules shared by all read queries.
|
|
|
|
* Source filtering happens at the evidence level: a claim is returned only if at least one document comes
|
|
from an allowed source, and only allowed evidence is shown.
|
|
* Claims merged into another claim (corroboration) are hidden; the survivor carries all evidence.
|
|
* Claims pending human review are hidden unless include_pending is set (moderation).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
from typing import Any
|
|
|
|
VISIBLE = ("c.merged_into IS NULL AND (c.review_status = 'published' OR "
|
|
"(%(include_pending)s AND c.review_status = 'pending'))")
|
|
# Votes on amendments and parts of a text only appear where someone asks for them: they would bury everything else.
|
|
NOT_PART_VOTE = "NOT COALESCE((c.data->>'part_vote')::boolean, FALSE)"
|
|
|
|
|
|
@dataclass
|
|
class SourceFilter:
|
|
exclude_sources: list[str] = field(default_factory=list)
|
|
min_trust: int = 0
|
|
|
|
def sql(self, alias: str = "s") -> tuple[str, dict[str, Any]]:
|
|
return (
|
|
f"(NOT ({alias}.slug = ANY(%(exclude_sources)s)) AND {alias}.default_trust >= %(min_trust)s)",
|
|
{"exclude_sources": self.exclude_sources, "min_trust": self.min_trust},
|
|
)
|
|
|
|
|
|
def evidence_json(source_sql: str) -> str:
|
|
"""Lateral subquery aggregating the allowed evidence of claim `c`."""
|
|
return f"""
|
|
CROSS JOIN LATERAL (
|
|
SELECT jsonb_agg(jsonb_build_object(
|
|
'url', d.url, 'title', d.title, 'source', s.slug, 'source_name', s.name, 'source_kind', s.kind,
|
|
'published_at', d.published_at, 'quote', e.quote, 'stance', e.stance, 'archive_url', d.archive_url)
|
|
ORDER BY s.default_trust DESC, d.published_at) AS evidence,
|
|
count(DISTINCT s.id) AS source_count
|
|
FROM claim_evidence e JOIN document d ON d.id = e.document_id JOIN source s ON s.id = d.source_id
|
|
WHERE e.claim_id = c.id AND {source_sql}
|
|
) ev"""
|