Skip to content

Ticket #2539 :: Task: Track documentation contributions and derive the Documenter achievement from them - #2641

Open
herzog0 wants to merge 19 commits into
teo/badges-docsfrom
teo/2539-source-documentation
Open

Ticket #2539 :: Task: Track documentation contributions and derive the Documenter achievement from them #2641
herzog0 wants to merge 19 commits into
teo/badges-docsfrom
teo/2539-source-documentation

Conversation

@herzog0

@herzog0 herzog0 commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Issue: #2539

⚠️ Base branch is teo/badges-docs

Summary & Context

Makes Documenter an automatic achievement. Nothing in the site recorded who wrote
documentation, so the badge could only be granted by hand. The commit importer already clones
every library repo, so asking git for per-file statistics in the same call costs one flag and no
extra API traffic. Each commit now carries a count of the documentation files it touched, and the
achievement counts commits with a non-zero count.

Getting there needed one fix first. An automatic grant identified its evidence by the row it
pointed at, and commit row ids are not stable: the importer deletes and re-creates them, and the
same commit is stored once per release range covering it. So grants were being orphaned and counts
inflated. Grants now carry the source's own id instead (a commit sha, a library key, a review
fingerprint). That part is invisible on screen but is the reason the new source can be trusted.

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

Changes

  • Automatic grants gain a dedup_info column and are matched on it instead of on a row id.
  • Every source iterator now names its evidence; the key is required, not optional.
  • Review can produce its own dedup fingerprint, which the import command used to keep private.
  • The commit importer reads per-file statistics and stores a doc-file count on each commit.
  • Documentation path rules live in one new module, with the classifier and rename handling.
  • A destructive commit re-import now discards the grants it would otherwise orphan.
  • The Documenter source is wired and selectable wherever a source can be named.
  • Two migrations: the grant column, and the count on Commit.

‼️ Risks & Considerations ‼️

  • Existing environments need clearing, not migrating. Grants written before this branch carry
    no key, so a reconcile replaces them rather than adopting them. Nothing is in production; staging
    and QA should have their badge tables emptied and rebuilt. I (Teo) will be doing that.
  • Counts will drop where they were inflated. That is the correct number arriving, but it reads
    like a regression.
  • The key format is now a contract. Changing how a source names its evidence later invalidates
    every grant it fed. Cheap to change now, expensive after launch.
  • Old commits read low until re-imported. The count only lands when a library is imported
    again, so doc work predating this shows as zero until then.
  • "Update Commits" still deletes and reinserts the whole table. Discarding grants first makes
    it safe for achievements; whether the button should stop doing that is an open question on the
    ticket.
  • The Documenter description still talks about Antora and BoostLook while the classifier counts any
    doc path. Those two should be settled together before a production backfill.

Screenshots

n/a - no UI. The badge already renders wherever badges render.

Peer-review testing steps

Setup: just load_production_data, just migrate, docker compose up.

  1. Updating commit authors: run the following first:
docker compose exec -T celery-worker python manage.py shell -c "
from libraries.tasks import update_commit_authors_users
update_commit_authors_users()
"
  1. The rules. In just manage shell:

    from libraries.doc_paths import is_doc_path
    [is_doc_path(p) for p in ["doc/index.adoc", "README.md", "doc/html/index.html", "meta/libraries.json"]]
    # [True, False, False, False]
  2. A real import. just manage import_commits --key mp11, then:

    -- docker compose exec db psql -U postgres postgres
    SELECT count(*) FILTER (WHERE docs_files_changed > 0) AS doc_commits,
           count(*)                                       AS total
    FROM libraries_commit c
    JOIN libraries_libraryversion lv ON lv.id = c.library_version_id
    JOIN libraries_library l ON l.id = lv.library_id
    WHERE l.key = 'mp11';
    
    -- Merges never count.
    SELECT count(*) FROM libraries_commit WHERE is_merge AND docs_files_changed > 0;  -- 0
    
    -- The stats must not have leaked into the message.
    SELECT count(*) FROM libraries_commit WHERE message LIKE '%' || chr(9) || '%';    -- 0

    Spot-check one sha against the repo: git show --numstat <sha> and count the doc paths yourself.

  3. Backfill. just manage backfill_achievements --source documentation, then run it a
    second time. The second run must report added 0.

    SELECT count(*), count(DISTINCT dedup_info)
    FROM badges_userachievement ua
    JOIN badges_achievement a ON a.id = ua.achievement_id
    WHERE a.slug = 'documentation';   -- equal
  4. Pk churn is a non-event. Note the code-commits and documentation grant counts, then
    just manage import_commits --key mp11 --clean and backfill both sources again. Counts
    unchanged, and no grant left pointing at a deleted row:

    SELECT count(*) FROM badges_userachievement ua
    JOIN django_content_type ct ON ct.id = ua.source_content_type_id
    LEFT JOIN libraries_commit c ON c.id = ua.source_object_id
    WHERE ct.app_label = 'libraries' AND ct.model = 'commit' AND c.id IS NULL;  -- 0
  5. Reconcile. just manage reconcile_achievements --dry-run. Over freshly backfilled
    data every source reports added 0, removed 0.

QA notes

Everything here is doable from the admin at /admin/. You need a member who has written
documentation in a Boost library and whose commit email is linked to their account; ask the
developer to point you at one, or to run the import for a library you can then use.

  1. Documenter is automatic now. Open Badges. The Documenter row's Automatic column
    used to say no and now says yes. Only Regular and Publisher still say no.

  2. It appears as a source you can choose. Open User achievements and press Backfill
    achievements
    . Documentation is now in the source list. Pick it and run it. The status
    finishes in place, no reload needed.

  3. Grants arrived, and say where from. Still on User achievements, filter Achievement to
    Documentation. Each row's Source column links to the commit that earned it; click one and
    check the commit message looks like documentation work. Open a row: there is a read-only
    Dedup info field showing the commit's id from git. Nothing except Grant notes should be
    editable.

  4. The badge was awarded. Open User badges. The members from step 3 hold Documenter at
    whichever tier their count reaches. Click a member's name for their per-member page: it shows
    the valid grant count and how many more are needed for the next tier.

  5. Running it twice changes nothing. Press Backfill achievements on Documentation again,
    then open Achievement sync runs. Two documentation rows, the second with Added 0, both
    naming you under Triggered by. This is the most important check in this list: it is what
    stops the weekly job doubling everyone's count.

  6. Search by commit id. Copy the Dedup info value from a grant in step 3 and paste it into
    the search box on User achievements. It finds that grant. This did not work before.

  7. The profile still looks right. Log in as (or impersonate) a member holding Documenter and
    open their profile. The badge renders with the others. Check light and dark mode, and check that
    a member with Hide badges ticked in their preferences still shows none.

  8. Manual grants are untouched. Grant Documentation to someone by hand with a note, then run
    Backfill achievements on Documentation again. The manual grant is still there, still shows
    your note, and still names you as the granting admin.

If you see zero grants after step 2, that is not necessarily a bug: the achievement only credits
commits whose author is linked to a member account. Ask the developer to confirm any exist on your
database before treating it as a failure.

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, pre-commit run -a clean
  • Two migrations included
  • No additional GitHub API calls: the data comes from the clone the importer already makes
  • Suite: 1575 passed / 44 skipped. 12 failures are pre-existing and fail identically on
    the base branch: 11 environment-related (a quoted AWS_REGION in the local env file, and
    path-matcher tests that reach S3), plus one Django connection-pool teardown error in a
    timezone test.

Summary by CodeRabbit

  • New Features

    • Documentation contributions can now earn badges automatically.
    • Commit records track documentation files changed.
    • Automatic achievements use stable evidence identifiers to prevent duplicate awards and support cleanup of outdated grants.
    • Review imports now use consistent duplicate detection.
  • Bug Fixes

    • Improved handling of re-imported commits, renamed libraries, duplicate legacy achievements, and concurrent updates.
    • Documentation detection now excludes generated, ignored, and non-documentation files.
  • Documentation

    • Updated badge administration guidance and manual-grant information.

@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 39849d00-b4e1-43bd-96fd-f49de0df0376

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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: ff843da4-80b9-480c-ad16-3ec66b585cda

📥 Commits

Reviewing files that changed from the base of the PR and between 13f8a1f and 3ca5e13.

📒 Files selected for processing (20)
  • badges/admin.py
  • badges/migrations/0004_userachievement_dedup_info.py
  • badges/models.py
  • badges/services.py
  • badges/sources.py
  • badges/tests/fixtures.py
  • badges/tests/test_admin_badge_config.py
  • badges/tests/test_dedup_keys.py
  • badges/tests/test_sources.py
  • badges/tests/test_sync_log.py
  • docs/badges-admin.md
  • libraries/doc_paths.py
  • libraries/github.py
  • libraries/migrations/0044_commit_docs_files_changed.py
  • libraries/models.py
  • libraries/tests/test_doc_paths.py
  • libraries/tests/test_github.py
  • versions/management/commands/import_reviews.py
  • versions/models.py
  • versions/review_keys.py

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


📝 Walkthrough

Walkthrough

The pull request adds stable deduplication keys for automatic achievements, tracks documentation changes during Git imports, wires documentation commits to the Documenter badge, and centralizes review fingerprint generation.

Changes

Badge deduplication and documentation sources

Layer / File(s) Summary
Automatic grant identity contract
badges/models.py, badges/migrations/0004_userachievement_dedup_info.py, badges/admin.py
UserAchievement stores dedup_info. Automatic grants use conditional uniqueness on user, achievement, and deduplication data. The admin exposes the field for search and display.
Documentation change import
libraries/doc_paths.py, libraries/github.py, libraries/models.py, libraries/migrations/0044_commit_docs_files_changed.py, libraries/tests/*
Git numstat output is parsed and documentation paths are classified. Commits store docs_files_changed. Reimports update this field and remove grants tied to deleted commits.
Source keys and grant synchronization
badges/sources.py, badges/services.py, badges/tests/*, docs/badges-admin.md
Source iterators yield stable keys. _sync_source uses those keys to match, insert, deduplicate, and remove automatic grants. Documentation commits now provide the Documenter source.

Review identity reuse

Layer / File(s) Summary
Shared review fingerprint
versions/review_keys.py, versions/models.py, versions/management/commands/import_reviews.py
Review normalization and fingerprinting move to versions.review_keys. Review.dedup_key and review imports use the shared implementation.

Estimated code review effort: 4 (Complex) | ~60 minutes

Merge Risk: ⚪ Minimal · up to 3ca5e

This change adds automatic documentation achievement tracking and related persistence updates; no actionable merge-blocking risk remains, so it is merge-ready after normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant GitRepository
  participant libraries.github
  participant libraries.doc_paths
  participant Commit
  participant badges.sources
  participant badges.services
  participant UserAchievement

  GitRepository->>libraries.github: Return git log --numstat output
  libraries.github->>libraries.doc_paths: Count documentation files
  libraries.doc_paths-->>libraries.github: Return documentation-file count
  libraries.github->>Commit: Store docs_files_changed
  badges.sources->>badges.services: Yield user, commit, and commit SHA
  badges.services->>UserAchievement: Create or update keyed grant
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 80.77% which is sufficient. The required threshold is 80.00%.
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.
Description check ✅ Passed The description covers the issue, context, changes, risks, screenshots, testing guidance, QA notes, and self-review checklist.
Title check ✅ Passed The title clearly identifies the main change: making documentation contributions drive the automatic Documenter achievement.
✨ 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/2539-source-documentation

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 force-pushed the teo/2539-source-documentation branch from 27ed0df to 657de79 Compare August 21, 2026 14:48
@herzog0
herzog0 marked this pull request as ready for review August 21, 2026 15:59
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: Track documentation contributions and derive the Documenter achievement from them

1 participant