Skip to content

Handle early negative source votes#291

Open
ohld wants to merge 4 commits into
productionfrom
codex/moderator-source-vote-early-reject
Open

Handle early negative source votes#291
ohld wants to merge 4 commits into
productionfrom
codex/moderator-source-vote-early-reject

Conversation

@ohld
Copy link
Copy Markdown
Member

@ohld ohld commented May 20, 2026

Summary

  • close moderator source polls early after 90 minutes when they have 0 likes and at least 6 dislikes
  • edit closed poll messages with source context, final vote counts, and unpin the closed vote
  • keep the source/candidate rejection reason in DB metadata and try to post the next candidate
  • preserve useful local duplicate-cleanup work: resolve exact file-id duplicates and OCR duplicates after Describe Memes

Verification

  • ruff check scripts/serve_flows.py specs/moderator-community-loop.md src/storage/source_voting.py src/tgbot/handlers/moderator/source_candidates.py tests/storage/test_source_voting.py tests/tgbot/test_source_candidate_vote_handler.py src/flows/storage/describe_memes.py src/flows/storage/memes.py src/storage/service.py tests/storage/test_duplicate_resolution.py
  • python -m compileall -q scripts/serve_flows.py src/storage/source_voting.py src/tgbot/handlers/moderator/source_candidates.py tests/storage/test_source_voting.py tests/tgbot/test_source_candidate_vote_handler.py src/flows/storage/describe_memes.py src/flows/storage/memes.py src/storage/service.py tests/storage/test_duplicate_resolution.py
  • pytest tests/tgbot/test_source_candidate_vote_handler.py

Operational note

Prod currently has poll #4 for https://t.me/ravememe open with 0 likes / 8 dislikes. The available DB credential here is analyst_readonly, so I did not mutate prod DB directly. After merge/deploy, the source voting cycle should close it through the write-enabled app environment and post the next poll.

@ohld
Copy link
Copy Markdown
Member Author

ohld commented May 20, 2026

STAFF ENGINEER REVIEW: CHANGES REQUESTED — two blockers before this can land.

  1. Early-reject vote callbacks are not idempotent under concurrent dislikes. Two moderators can submit the threshold-crossing dislikes at nearly the same time; both callbacks can read the poll as open, both can close it because the status update is not guarded on status = 'open', and both can call post_new_source_candidate_poll. The second replacement poll creation can hit uq_meme_source_candidate_poll_active_global and turn a moderator callback into a webhook error. Make the close/post-next path idempotent before merging, for example with a compare-and-swap close update and/or a re-check for an active replacement poll before posting.

  2. CI is red: lint fails because ruff format --check src/ tests/ would reformat tests/storage/test_source_voting.py.

Security/structural scan notes: no new secrets, dependency/workflow changes, or new SQL string interpolation found in the changed files. GitHub test passed. Auto-merge was disabled before posting this signal.

@ohld
Copy link
Copy Markdown
Member Author

ohld commented May 20, 2026

STAFF ENGINEER REVIEW: CHANGES REQUESTED — The early-reject callback is not idempotent under concurrent moderator votes. Two threshold-crossing callbacks can both close/post and the second replacement poll can hit uq_meme_source_candidate_poll_active_global, turning a normal vote into a webhook error. Please make close/post idempotent, for example with a status-guarded close or replacement-poll reuse, then re-request review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant