Skip to content

Awarn and leaderboard improve - #1

Merged
Perl404 merged 1 commit into
mainfrom
awarn-and-leaderboard-improve
Apr 30, 2026
Merged

Perl404 merged 1 commit into
mainfrom
awarn-and-leaderboard-improve

Conversation

@Perl404

@Perl404 Perl404 commented Apr 30, 2026

Copy link
Copy Markdown
Owner

Summary by Sourcery

Introduce configurable warning thresholds per department and enhance guild-wide leaderboard visibility and formatting.

New Features:

  • Add a global leaderboard mode that aggregates points across departments with per-department breakdowns and mini progress bars.
  • Allow departments to define a maximum awarn weight, used to scale warning bars and severity colors consistently per department.
  • Add an optional icon emoji field for shop items to support richer shop presentation.

Enhancements:

  • Improve leaderboard command UX with optional department selection, clearer Russian descriptions, and better handling of empty or inaccessible data.
  • Show users their own rank outside the visible leaderboard range for both department and global leaderboards.
  • Refine awarn severity coloring to be based on relative warning load instead of fixed absolute thresholds, and propagate the new scaling through DM, log, public, and admin views.
  • Expose department warn limits in the department overview and creation flows, including a new admin command to adjust the limit.
  • Ensure long leaderboard descriptions are truncated safely within Discord embed limits.

Build:

  • Bump database schema to v10 with migrations for shop item icons and per-department maximum awarn weight.

@sourcery-ai

sourcery-ai Bot commented Apr 30, 2026

Copy link
Copy Markdown

Reviewer's Guide

Refactors the /leaderboard command to support both per-department and global leaderboards with richer embeds, introduces configurable per-department warn weight limits that drive awarn severity coloring and gauges, and extends the database schema and department/shop admin tooling to support these new capabilities (including shop item icons).

Sequence diagram for the updated /leaderboard command

sequenceDiagram
    actor User
    participant Discord
    participant PointsCog
    participant Database

    User->>Discord: invoke /leaderboard [department?, limit]
    Discord->>PointsCog: leaderboard(interaction, department, limit)

    PointsCog->>Database: require_configured_guild
    Database-->>PointsCog: configured?
    alt not configured or not in guild
        PointsCog-->>Discord: error embed (only works in guild)
    else configured
        PointsCog->>PointsCog: branch on department is not None
        alt single department mode
            PointsCog->>Database: get_department_by_key / resolve_department
            Database-->>PointsCog: Department or None
            alt department not found
                PointsCog-->>Discord: unknown department error
            else department found
                PointsCog->>Database: _can_view_leaderboard(caller, dept.id)
                Database-->>PointsCog: allowed?
                alt not allowed
                    PointsCog-->>Discord: "Нет доступа" error embed
                else allowed
                    PointsCog->>Database: dept_leaderboard(dept.id, limit)
                    Database-->>PointsCog: list of (user_id, points)
                    alt empty rows
                        PointsCog-->>Discord: info "Доска пуста" embed
                    else has rows
                        PointsCog->>Database: dept_user_rank(dept.id, caller.id)
                        PointsCog->>Database: get_dept_balance(caller.id, dept.id)
                        Database-->>PointsCog: rank, caller_points
                        PointsCog->>PointsCog: build bars with _mini_bar and lines
                        PointsCog->>Discord: send embed (single dept leaderboard)
                    end
                end
            end
        else global mode (all departments)
            PointsCog->>Database: list_departments(guild.id)
            Database-->>PointsCog: list of Department
            alt no departments
                PointsCog-->>Discord: info "Нет департаментов" embed
            else departments exist
                PointsCog->>Database: is_admin / is_auditor / is_curator_of_department / get_dept_balance
                Database-->>PointsCog: visible departments for caller
                alt caller sees no departments and not privileged
                    PointsCog-->>Discord: info "Нет данных" embed
                else has visibility or privileged
                    PointsCog->>Database: guild_leaderboard(guild.id, limit, visible_dept_ids)
                    Database-->>PointsCog: list of (user_id, total, breakdown)
                    alt no rows
                        PointsCog-->>Discord: info "Доска пуста" embed
                    else rows
                        PointsCog->>PointsCog: build per user bars and breakdown lines
                        PointsCog->>Database: guild_user_total_rank(guild.id, caller.id, visible_dept_ids)
                        Database-->>PointsCog: (rank, total)
                        PointsCog->>Discord: send embed (global leaderboard)
                    end
                end
            end
        end
    end
Loading

ER diagram for departments, balances, and shop_items with new fields

erDiagram
    DEPARTMENTS {
        int id PK
        int guild_id
        text key
        text name
        int sort_order
        datetime created_at
        int log_channel_id
        real max_awarn_weight
    }

    DEPARTMENT_BALANCES {
        int user_id
        int department_id FK
        int points
    }

    SHOP_ITEMS {
        int guild_id
        int department_id FK
        int role_id
        int price
        int duration_days
        text description
        text icon_emoji
        real price_growth
    }

    DEPARTMENTS ||--o{ DEPARTMENT_BALANCES : has
    DEPARTMENTS ||--o{ SHOP_ITEMS : offers
Loading

Class diagram for updated Department, ShopItem, and Database methods

classDiagram
    class Department {
        int id
        int guild_id
        str key
        str name
        int sort_order
        datetime created_at
        int log_channel_id
        float max_awarn_weight
    }

    class ShopItem {
        int guild_id
        int department_id
        int role_id
        int price
        int duration_days
        str description
        str icon_emoji
        float price_growth
        int effective_price(prior_count)
    }

    class Database {
        int CURRENT_SCHEMA_VERSION
        run()
        _migrate_to_v9()
        _migrate_to_v10()
        create_department(guild_id, key, name, sort_order, max_awarn_weight) Department
        get_department(department_id) Department
        get_department_by_key(guild_id, key) Department
        list_departments(guild_id) list~Department~
        set_department_log_channel(department_id, channel_id)
        set_department_max_awarn_weight(department_id, max_awarn_weight)
        get_user_dept_balances(guild_id, user_id) list~tuple~
        dept_leaderboard(department_id, limit) list~tuple~
        guild_leaderboard(guild_id, limit, dept_ids) list~tuple~
        guild_user_total_rank(guild_id, user_id, dept_ids) tuple
        dept_user_rank(department_id, user_id) int
        upsert_shop_item(guild_id, department_id, role_id, price, duration_days, description, icon_emoji)
        list_shop_items(guild_id, department_id) list~ShopItem~
        get_shop_item(guild_id, department_id, role_id) ShopItem
        _department_from_row(row) Department
        _shop_item_from_row(row) ShopItem
    }

    Database "1" --> "*" Department : manages
    Database "1" --> "*" ShopItem : manages
    Department "1" --> "*" ShopItem : optional_shop_items
Loading

File-Level Changes

Change Details Files
Refactor /leaderboard to support optional department argument, global per-guild leaderboard aggregation, and safer Discord embed sizing.
  • Add _mini_bar helper to render compact inline progress bars relative to the top score.
  • Add _join_truncated helper to safely join leaderboard lines within Discord's 4096-character description limit.
  • Change /leaderboard signature to accept optional department and default limit, with improved Russian descriptions.
  • Implement single-department mode with access checks, per-user rank lookup, caller highlighting, and thumbnails/footers based on guild and top user.
  • Implement global leaderboard mode aggregating across departments, filtering visible departments based on user roles/balances or admin/auditor privileges, and showing per-department breakdown per user.
  • Add guild_leaderboard and guild_user_total_rank DB methods to compute totals, breakdowns, and ranks, including scoped to a subset of department IDs.
src/spesobot/cogs/points.py
src/spesobot/db.py
Introduce per-department configurable maximum awarn weight and wire it into awarn displays (colors and weight bars).
  • Extend Department dataclass and schema with max_awarn_weight, including migration _migrate_to_v10 and plumbing through create/get/list/resolution helpers.
  • Add set_department_max_awarn_weight DB API and expose it via new /department warn_limit admin command and extended /department create options.
  • Update awarns flows (give/remove/perform_unawarn/get/set) and embed builders/_send_dm to pass department max_awarn_weight into weight_bar and severity_color.
  • Adjust awarn summary embed in /awarn get to color by worst per-department ratio and show per-department bars relative to each department's max_awarn_weight.
  • Show max_awarn_weight in /department view output for each department.
src/spesobot/db.py
src/spesobot/cogs/awarns.py
src/spesobot/cogs/departments.py
Extend shop items with optional icon_emoji and migrate existing data.
  • Add icon_emoji field to ShopItem dataclass and _migrate_to_v9 schema migration for shop_items.icon_emoji with default ''.
  • Update upsert_shop_item to accept and persist icon_emoji and ensure ON CONFLICT updates it while leaving price_growth unchanged.
  • Update list_shop_items and get_shop_item queries and _shop_item_from_row to hydrate icon_emoji while remaining backwards compatible with older row shapes.
src/spesobot/db.py
Change severity_color semantics from absolute awarn weight thresholds to ratio-based thresholds using a configurable max weight.
  • Update severity_color signature to take weight and max_weight, computing color based on weight/max_weight ratio into 4 buckets (green/gold/orange/red).
  • Update all call sites to pass either department max_awarn_weight or in the global awarn view, the worst ratio with a normalized max of 1.0.
  • Ensure behavior when max_weight <= 0 degrades safely to BRAND_ERROR.
src/spesobot/format.py
src/spesobot/cogs/awarns.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@Perl404
Perl404 merged commit 393fee0 into main Apr 30, 2026
1 of 2 checks passed
@Perl404
Perl404 deleted the awarn-and-leaderboard-improve branch April 30, 2026 20:45

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • In _join_truncated, the length check if total + needed + (len(sep) if parts else 0) + len(ellipsis) > max_len appears to double-count the separator (it’s already included in needed), which can cause earlier-than-necessary truncation; consider re-deriving this condition so each separator is only counted once.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `_join_truncated`, the length check `if total + needed + (len(sep) if parts else 0) + len(ellipsis) > max_len` appears to double-count the separator (it’s already included in `needed`), which can cause earlier-than-necessary truncation; consider re-deriving this condition so each separator is only counted once.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 5 additional findings.

Open in Devin 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