Skip to content

fix: finalize a campaign after its ranking round was finalized; name "close with/without report" - #684

Open
lgelauff wants to merge 3 commits into
masterfrom
fix/644-close-campaign-after-ranking-round
Open

lgelauff wants to merge 3 commits into
masterfrom
fix/644-close-campaign-after-ranking-round

Conversation

@lgelauff

Copy link
Copy Markdown
Collaborator

Finalizing the ranking round with the round's own button left the campaign impossible to finalize, and so without a report (#644). This PR fixes that, and makes the two ways to close a campaign visible on the campaign page.

It builds on two contributions, credited as co-authors of the first commit: @SSpirate11 (#672) and @ademolaomosanya (#408). Thank you both.

Backend

finalize_campaign (admin_endpoints.py):

A finalized campaign keeps meaning "its final results are stored", as decided in #169. So a campaign that ends on a yes/no or rating round is still refused, now with a hint to archive it instead. Whether such campaigns should get a report is #680.

save_results_summary (rdb.py) is split out of finalize_ranking_round. It updates the campaign's one summary instead of adding a second one, so a reopened campaign can be finalized again (from #672).

Finalizing before any ranking ballot is in now returns a 400 ("no ranking ballots have been submitted yet") instead of a 500 (#681). With no ballots, get_round_ranking_list used to pass an empty list to SchulzeNPR, which recursed until RecursionError. It now returns an empty ranking for that case.

Frontend (campaign page)

  • Close with report: finalize. Shown only while the campaign is active and its last round is a ranking round.
  • Close without report: archive. "Archive" keeps its label for finalized campaigns, and Reopen unarchives.
  • Help text when no report is possible: a report needs a ranking round as the last round, and the results of each round stay on the round page.
  • New i18n keys, documented in qqq.json.
  • The rroundResults typo fix, which shows the cancelled-task count again (from fix: allow closing campaign after any finalized round #408).

Tests

montage/tests/test_finalize_campaign.py, 6 tests:

All 6 fail on master. Full suite: 177 passed, 3 xfailed. Frontend lint, prettier and build pass.

Checked in a headless browser against local dev servers: the buttons and help text for a campaign ending on a ranking round, one ending on a yes/no round, and an archived campaign. Not checked: the finalized state with a real report.

Fixes #644. Fixes #681. Supersedes #672 and #408. #143 is covered by archiving; see the comment there.

Written by Claude (Claude Code) on behalf of @lgelauff.

🤖 Generated with Claude Code

lgelauff and others added 3 commits October 31, 2026 18:09
Finalizing the ranking round with the round's own button left the
campaign impossible to finalize ("no active rounds"), and so without a
report (#644).

finalize_campaign now also accepts a campaign whose last round is a
finalized ranking round. It stores the results summary from that round
without touching the round itself. A finalized campaign keeps meaning
"its final results are stored", so a campaign that ends on a yes/no or
rating round is still refused, with a hint to archive it instead.

- save_results_summary: split out of finalize_ranking_round; updates
  the campaign's existing summary instead of adding a second one, so a
  reopened campaign can be finalized again.
- Refuse to finalize a campaign that is already finalized.
- RoundInfo.vue: fix the rroundResults typo that hid the cancelled-task
  count.

Builds on #672 (summary update, the already-finalized
refusal, the #644 case) and #408 (the typo fix).

Fixes #644

Co-authored-by: Sanjai Siddharthan <sanjaisiddharth2002@gmail.com>
Co-authored-by: ademolaomosanya <omosanyaademola@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Close campaign" (finalize) and "Archive" both take a campaign off the
default list, but only finalizing stores a report, and only when the
last round is a ranking round. Make that visible on the campaign page:

- "Close with report" (finalize): shown only while the campaign is
  active, not archived, and its last round is a ranking round.
- "Close without report" (archive) for an active campaign; a finalized
  campaign keeps "Archive". "Reopen" unarchives an active campaign.
- Help text when no report is possible: a report needs a ranking round
  as the last round, and round results stay on the round page.

New i18n keys with qqq.json documentation; the existing
montage-close-campaign, montage-archive and montage-unarchive keys stay.

Refs #644, #143

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Finalizing a campaign whose ranking round had files but no submitted
ballot failed with a 500: get_round_ranking_list passed an empty list
to SchulzeNPR, which recursed until RecursionError. The results
preview already refused this case; finalizing did not.

- save_results_summary (used by both finalize paths) raises
  InvalidAction when the round has no completed ballot, so the
  coordinator gets a 400 with a reason and nothing changes.
- get_round_ranking_list returns an empty list for no ballots instead
  of calling SchulzeNPR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lgelauff added a commit that referenced this pull request Nov 2, 2026
Campaign page buttons are "Close with report" and "Close without report"
(#684); the refusal now says "close it instead: with a report (needs a
ranking round as the last round) or without a report".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

1 participant