Skip to content

Story #2586 :: Task: Wire the Library Maintenance achievement, counting libraries and not versions - #2587

Merged
herzog0 merged 2 commits into
developfrom
teo/2541-source-library-maintenance
Aug 28, 2026
Merged

Story #2586 :: Task: Wire the Library Maintenance achievement, counting libraries and not versions#2587
herzog0 merged 2 commits into
developfrom
teo/2541-source-library-maintenance

Conversation

@herzog0

@herzog0 herzog0 commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Issue: #2586

⚠️ Base branch is teo/2541-source-library-authoring

Summary & Context

Wires the Library Maintenance achievement. The one thing worth reviewing here is the grain:
maintainers are recorded per LibraryVersion, but the badge counts libraries maintained
(1 / 2 / 5 / 10 / 20), so the iterator deduplicates across versions and yields the Library as
the achievement source.

Without that, a maintainer of one library with 40 releases would hold diamond.

  • Figma link: n/a
  • Link to components/page: n/a

Changes

  • _iter_library_maintenance walks LibraryVersion with its maintainers prefetched and yields
    (user, library) once per (user, library) pair, tracking what it has already seen.
  • Registered in BACKFILL_ITERATORS.
  • test_iter_library_maintenance_dedupes_versions - three versions of one library yield exactly
    one pair.
  • test_backfill_library_maintenance - two versions, one grant, one badge.

‼️ Risks & Considerations ‼️

  • The dedup set is held in memory for the whole walk. It is one tuple per (user, library) pair,
    bounded by the number of maintainer relationships, not by the number of versions - a few
    thousand entries at Boost's scale.
  • The source object recorded on the grant is the Library, not the LibraryVersion. This is
    what makes the grant idempotent under unique_automatic_user_achievement_source and what lets
    reconciliation match it. An earlier iteration of this feature recorded versions and had to be
    cleaned up with a data migration; a fresh install never creates those rows.
  • Dropping a maintainer from every version of a library removes the grant on the next
    reconcile, the two-way command, not on a backfill. That is by design.

Screenshots

n/a - no UI.

Peer-review testing steps

The dedup is basically the whole PR, and it is visible on a changelist.

  1. The source is wired. /admin/badges/badge/ - the Maintainer row's Automatic column is a
    tick and its ladder reads 1 / 2 / 5 / 10 / 20.

  2. Make yourself a maintainer of one library, several times over.
    /admin/libraries/libraryversion/, filter by a single library, then open three of its versions
    and add your own user to Maintainers on each.

  3. Backfill. /admin/badges/userachievement/ -> Backfill achievements with Source set to
    Library Maintenance.

  4. Three versions, one grant. Filter that changelist by Achievement: Library Maintenance: you
    have exactly one row, and its Source column links to the library, not to any of the
    three versions. Without the dedup this step is where you would see three. /admin/badges/userbadge/
    shows Maintainer / Bronze; the per-member page (your name, linked from either badge changelist)
    reads one valid grant and 1 to go to Silver.

  5. A second library does move the count. Add yourself to Maintainers on one version of a
    different library and press Backfill again: two grants, and Maintainer / Silver is
    awarded. This is what proves the dedup is per (member, library) and not just "one grant per member".

  6. Removal is a reconcile, and it demotes. Drop yourself from all three versions of the first
    library. Backfill changes nothing. Then Reconcile achievements with Source on Library
    Maintenance
    : the preview reports one removal, Apply, and the Silver row is revoked with
    Count at revocation 1 while Bronze stays held. /admin/badges/achievementsyncrun/ shows the run
    with Removed 1, and the revoked badge's notes name it.

  7. Sanity-check against real data. Backfill All sources on a production copy, then filter
    /admin/badges/userbadge/ to Badge: Maintainer and Rank: Diamond. Every name there must genuinely
    maintain 20 or more libraries - filter /admin/badges/userachievement/ by Achievement: Library
    Maintenance
    , search their email, and count the rows, whose Source links must all be distinct
    libraries. Without the dedup, anyone maintaining a single long-lived library would be sitting in that
    Diamond list, which is the failure this PR exists to prevent.

Self-review Checklist

  • Tag at least one team member from each team to review this PR
  • Link this PR to the related GitHub Project ticket

Backend

  • Black + Ruff clean
  • No new models or migrations
  • Full suite green: 1336 passed / 43 skipped

Summary by CodeRabbit

  • New Features
    • Added automatic recognition of the Library Maintenance achievement for users who maintain libraries.
    • Prevented duplicate achievements when users maintain multiple versions of the same library.
    • Excluded sub-libraries from Library Maintenance achievement awards.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c59b5c53-8acf-4422-a712-c137a85050aa

📥 Commits

Reviewing files that changed from the base of the PR and between 0952859 and 90894ef.

📒 Files selected for processing (3)
  • badges/sources.py
  • badges/tests/test_commands.py
  • badges/tests/test_sources.py

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

Adds an automatic library maintenance achievement source. It deduplicates maintenance across library versions, excludes sub-libraries, registers the source, and validates achievement and badge creation.

Changes

Library maintenance achievement

Layer / File(s) Summary
Maintenance source and registration
badges/sources.py
Adds _iter_library_maintenance and registers it for AchievementSlug.LIBRARY_MAINTENANCE. The iterator yields one pair per maintained library and excludes sub-libraries.
Backfill validation
badges/tests/test_sources.py, badges/tests/test_commands.py
Tests verify version deduplication, sub-library exclusion, and creation of one UserAchievement with a matching UserBadge.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 90894

This localized change deduplicates library maintainers across versions while preserving the intended achievement source and is supported by targeted tests and a passing suite; no actionable merge-blocking risk remains.

Sequence Diagram(s)

sequenceDiagram
  participant LibraryVersion
  participant _iter_library_maintenance
  participant backfill_achievements
  participant UserAchievement
  participant UserBadge

  LibraryVersion->>_iter_library_maintenance: provide library versions and maintainers
  _iter_library_maintenance->>backfill_achievements: yield unique user and library pairs
  backfill_achievements->>UserAchievement: create library-maintenance achievement
  backfill_achievements->>UserBadge: create matching badge
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the Library Maintenance achievement and states the key behavior: counting libraries rather than library versions. It is somewhat long but remains specific and relevant.
Description check ✅ Passed The description is complete and directly matches the pull request objectives. It includes the issue, context, changes, risks, testing steps, screenshots status, and backend self-review results.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 10 functions across 3 files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch teo/2541-source-library-maintenance

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@herzog0 herzog0 changed the title feat: derive the library maintenance achievement per library maintained Story #2586 :: Task: Wire the Library Maintenance achievement, counting libraries and not versions Aug 6, 2026
@herzog0 herzog0 linked an issue Aug 6, 2026 that may be closed by this pull request
5 tasks
@herzog0
herzog0 force-pushed the teo/2541-source-library-maintenance branch from 32fb541 to 07a2b1c Compare August 11, 2026 15:16
@herzog0
herzog0 force-pushed the teo/2541-source-library-maintenance branch from 07a2b1c to d3c392d Compare August 11, 2026 16:48
@herzog0
herzog0 force-pushed the teo/2541-source-library-maintenance branch from d3c392d to 1696c2c Compare August 11, 2026 17:13
@herzog0
herzog0 force-pushed the teo/2541-source-library-maintenance branch from 1696c2c to a253833 Compare August 11, 2026 17:59
@julhoang
julhoang self-requested a review August 12, 2026 21:08

@julhoang julhoang left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great to me, thanks @herzog0 ! I just have 1 nit suggestion below for a test.

Comment on lines +57 to +65
def test_iter_library_maintenance_dedupes_versions(plain_user):
"""Maintaining many versions of one library yields a single pair."""
library = baker.make("libraries.Library")
for _ in range(3):
version = baker.make("libraries.LibraryVersion", library=library)
version.maintainers.add(plain_user)

pairs = list(sources._iter_library_maintenance())
assert pairs == [(plain_user, library)]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit suggestion: Perhaps we can update this test to add another library here, and assert that pairs == [(plain_user, library), (plain_user, another library)] to ensure we can cover that common case as well!

@herzog0
herzog0 force-pushed the teo/2541-source-library-maintenance branch from a253833 to 2703076 Compare August 13, 2026 14:44
@herzog0
herzog0 force-pushed the teo/2541-source-library-maintenance branch from 2703076 to 53d58b6 Compare August 14, 2026 15:26
@herzog0
herzog0 force-pushed the teo/2541-source-library-maintenance branch from 53d58b6 to 6319f28 Compare August 14, 2026 19:57
@herzog0
herzog0 force-pushed the teo/2541-source-library-maintenance branch from 6319f28 to 6f3b5a0 Compare August 14, 2026 20:07
@herzog0
herzog0 force-pushed the teo/2541-source-library-maintenance branch from 6f3b5a0 to 3d63eb3 Compare August 17, 2026 16:33
@herzog0
herzog0 force-pushed the teo/2541-source-library-maintenance branch 2 times, most recently from 105b2b5 to 54b0426 Compare August 17, 2026 20:21
@herzog0
herzog0 force-pushed the teo/2541-source-library-maintenance branch from 54b0426 to 929f3c3 Compare August 17, 2026 23:06
@herzog0
herzog0 force-pushed the teo/2541-source-library-maintenance branch from 929f3c3 to ee1f698 Compare August 18, 2026 14:28

@javiercoronadonarvaez javiercoronadonarvaez left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@herzog0
herzog0 force-pushed the teo/2541-source-library-maintenance branch from ee1f698 to 7434935 Compare August 21, 2026 14:48
@herzog0
herzog0 force-pushed the teo/2541-source-library-maintenance branch from 7434935 to 7b668c2 Compare August 24, 2026 13:40
@herzog0
herzog0 force-pushed the teo/2541-source-library-maintenance branch from 7b668c2 to 0ab9848 Compare August 24, 2026 19:22
@herzog0
herzog0 force-pushed the teo/2541-source-library-maintenance branch 2 times, most recently from 0ab9848 to b531f6c Compare August 25, 2026 14:16
@herzog0

herzog0 commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator Author

@kattyode

QA: Maintainer badge

The Maintainer badge starts filling itself in from the library data, instead of only being
grantable by hand.


What this change does

  • The Maintainer badge now reads the Maintainers field on library versions.
  • The badge counts libraries maintained, not releases. Maintainers are recorded release by
    release, so one library with 40 releases must still count as one.
  • The levels are 1 / 2 / 5 / 10 / 20 libraries.

The whole point of this change is that de-duplication. Without it, anyone maintaining a single
long-lived library would be sitting at Diamond. Test 2 and Test 5 are the ones that matter most.

What it does not do

  • It does not run on its own yet - somebody has to press a button.
  • Sub-libraries do not count, same as for Library Author. Maintaining only a sub-library earns
    nothing. Deliberate product decision, not a bug.
  • Nothing about the public website changes in this one.

Before you start

  1. Open /admin/badges/badge/ and find the
    Maintainer row.
  2. Its Automatic column must show a tick, and its levels must read 1 / 2 / 5 / 10 / 20.

If it still shows a cross, stop and tell Teo - the change is not deployed.

About the buttons: a status line appears under the button and updates by itself - Queued,
Running, Finished. No refresh needed. Stuck on Queued forever means the background job
system is not running in QA; tell Teo.


Test 1: make yourself a maintainer several times over

  1. Go to /admin/libraries/libraryversion/
    and filter to a single library.
  2. Open three of its versions and add your own user to Maintainers on each one. Save
    each.

Test 2: three versions, one achievement

  1. Go to /admin/badges/userachievement/,
    set Source to Library Maintenance, and press Backfill achievements.
  2. Filter the page by Achievement: Library Maintenance.

Expected:

  • You have exactly one row, not three.
  • Its Source column links to the library, not to any of the three versions. Click it and
    check.
  • /admin/badges/userbadge/ shows you
    holding Maintainer / Bronze.
  • Your per-member page (click your name from either badge list) reads one valid achievement and
    1 to go for Silver.

If you see three rows here, that is the bug this change exists to prevent. Report it.

Test 3: a different library does move the count

  1. Go back to /admin/libraries/libraryversion/
    and add yourself to Maintainers on one version of a different library.
  2. Press Backfill achievements on Library Maintenance again.

Expected: you now have two achievements and hold Maintainer / Silver.

This is what proves the rule is "one per library", not "one per person".

Test 4: running it twice changes nothing

Press Backfill achievements once more without changing any data, then open
/admin/badges/achievementsyncrun/.

Expected: the newest library-maintenance row says Added 0, and names you under
Triggered by.

Test 5: removing a maintainer demotes, but only on Reconcile

  1. Remove yourself from Maintainers on all three versions of the first library.
  2. Press Backfill achievements on Library Maintenance.

Expected: nothing changes. You still have two achievements and Silver. Backfill only ever adds.

  1. Now press Reconcile achievements with Source on Library Maintenance and read the
    preview.

Expected on the preview: 1 removal, and nothing has happened yet.

  1. Apply it.

Expected after applying:

  • One achievement is gone; the one for the second library remains.
  • Your Silver row on /admin/badges/userbadge/
    is marked revoked, with Count at revocation reading 1.
  • Your Bronze stays - you still maintain one library.
  • The revoked row's notes name the run, and
    /admin/badges/achievementsyncrun/
    shows that run with Removed 1.

Test 6: sanity-check against the real data (the most valuable check)

  1. Press Backfill achievements with Source on All sources.
  2. Go to /admin/badges/userbadge/ and
    filter to Badge: Maintainer and Rank: Diamond (in the panel at the right).
  3. Pick each name on that list and check it: filter
    /admin/badges/userachievement/
    by Achievement: Library Maintenance, search their email, and count the rows.

Expected: every Diamond holder genuinely has 20 or more rows, and each row's Source
link points at a different library.

If someone is sitting at Diamond with only a handful of libraries, or with several rows pointing at
the same library, the de-duplication is broken. That is the headline bug for this change.

If you can't find a Diamond ranked user for this achievement, you can redo the steps above checking Platinum users and they should have only 10 rows, Gold 5, Silver 2 and Bronze 1 (like shown in the ladder at the top)


Things that look wrong but are meant to be that way

  • Members who only maintain sub-libraries earn nothing.
  • The achievement links to the library rather than to the release you actually edited.
  • Backfill never removes anything.
  • Revoked badges stay visible in the admin rather than disappearing.

Reporting anything you find

Please include the run number from
/admin/badges/achievementsyncrun/,
the member's email with a screenshot of their per-member badge page, and which test above you
were on.

@herzog0
herzog0 force-pushed the teo/2541-source-library-maintenance branch from b531f6c to 16257a1 Compare August 26, 2026 17:49
Base automatically changed from teo/2541-source-library-authoring to develop August 26, 2026 17:51
@herzog0
herzog0 force-pushed the teo/2541-source-library-maintenance branch 4 times, most recently from a9d7c60 to 9dd3f99 Compare August 28, 2026 18:31
@herzog0
herzog0 force-pushed the teo/2541-source-library-maintenance branch from 9dd3f99 to 60458e8 Compare August 28, 2026 19:04
@herzog0
herzog0 merged commit f859d31 into develop Aug 28, 2026
1 of 5 checks passed
@herzog0
herzog0 deleted the teo/2541-source-library-maintenance branch August 28, 2026 19:18
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.

Task: Wire the Library Maintenance achievement, counting libraries and not versions

3 participants