Skip to content

feat(career): passport backend — genre badges computed from stars#935

Merged
byrongamatos merged 1 commit into
mainfrom
feat/career-passports
Jul 13, 2026
Merged

feat(career): passport backend — genre badges computed from stars#935
byrongamatos merged 1 commit into
mainfrom
feat/career-passports

Conversation

@byrongamatos

@byrongamatos byrongamatos commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

What

The passport backend — the badge-journey layer of career mode (Christian's career-mode v2 design, composed with the shipped venue/star system). Genre badges are computed on read from song_stats × the library's effective genre, exactly like venue stars — never stored.

  • Bronze badge = N genre songs at ≥ K★ (data-driven in plugins/career/passports.json, default 5 songs at 2★) + any configured virtuoso drill nodes (empty in v1 — ships songs-only).
  • GET /api/plugins/career/passports — per-instrument passport walls: badges, qualifying-song "ticket stubs", the library genre list (override-aware via the host's effective-genre SQL), drill status.
  • POST /passports/commit — instrument commitment (idempotent; only-gained-never-lost).
  • POST /passports/open — open a genre passport (implies commitment; permissive server, ceremony ordering is the UI's job).
  • POST /drill-state — intake for the relayed Virtuoso virtuoso.progress snapshot (the career frontend subscribes to the virtuoso:progress bus event that currently fires into a void — UI lands in the follow-up PR).

Design points

  • Instrument attribution reuses progression.instrument_for_arrangement via the song_stats.arrangement index — a bass performance never credits a guitar badge.
  • Non-graded instruments (bass, drums — where note-detect can't fairly grade pocket/feel) render shown_not_judged: repertoire, never a false badge denial.
  • Persisted state (commitments, opened passports, drill snapshot) lives under CONFIG_DIR/career/ and rides the settings export/import bundle via settings.server_files; a minimal settings.html documents it. Badges themselves are never persisted.
  • Same dead-song JOIN filter as _stars() — orphaned stats can't feed stubs.

Testing

  • 10 new HTTP-level tests in tests/plugins/career/test_passports.py (badge earned/in-progress, instrument split, per-instrument best-accuracy merge, orphan exclusion, genre-rack case collapse, commit/open idempotence + validation, drill gating, snapshot validation). Full backend suite: 2448 passed.
  • Verified live against a native server with seeded stats (badge minted at 5×2★, bass split correct, drill intake persists).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added Career passports for tracking progress by instrument and genre.
    • Added badge eligibility based on song performance and practice-drill progress.
    • Added support for committing instruments, opening genre passports, and syncing drill progress.
    • Added Career settings details and included saved progress in Settings export/import.
  • Documentation

    • Documented the new Career passport functionality and available endpoints.

The badge-journey layer on top of career stars (Christian's career-mode
v2 design, composed with the shipped venue system). Badges are computed
on read from song_stats × the library's effective genre — never stored:
Bronze = N genre songs at min_stars (data-driven in passports.json,
default 5 songs at 2★) plus any configured virtuoso drill nodes.

New endpoints under /api/plugins/career/:
- GET  /passports        passport walls per instrument: badges, ticket
                         stubs (qualifying songs), library genres, drills
- POST /passports/commit instrument commitment (idempotent wax seal)
- POST /passports/open   open a genre passport (implies commitment)
- POST /drill-state      intake for the relayed virtuoso.progress
                         snapshot (career's frontend listens on the bus)

Instrument attribution reuses progression.instrument_for_arrangement via
the song_stats arrangement index; the genre column goes through the
host's override-aware effective-genre SQL. Non-graded instruments (bass,
drums) render shown-not-judged — repertoire, never a false badge denial.

Persisted state (commitments, opened passports, drill snapshot) lives
under CONFIG_DIR/career/ and rides the settings export bundle via
settings.server_files; a minimal settings.html documents it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

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: 9ff81721-8028-4ade-bc41-8a84d484ab55

📥 Commits

Reviewing files that changed from the base of the PR and between 342def3 and e1a534a.

📒 Files selected for processing (7)
  • CHANGELOG.md
  • plugins/career/passports.json
  • plugins/career/plugin.json
  • plugins/career/routes.py
  • plugins/career/settings.html
  • tests/plugins/career/conftest.py
  • tests/plugins/career/test_passports.py

📝 Walkthrough

Walkthrough

Adds configurable Career passports with computed badge progress, persisted commitments and drill snapshots, new API endpoints, settings metadata, and comprehensive backend tests.

Changes

Career passports

Layer / File(s) Summary
Passport configuration and plugin wiring
plugins/career/passports.json, plugins/career/plugin.json, plugins/career/routes.py, plugins/career/settings.html, CHANGELOG.md
Defines badge and instrument requirements, registers settings and persisted Career state, and documents the new passport APIs and storage behavior.
Passport computation and APIs
plugins/career/routes.py
Computes genre and instrument progress from song metadata, applies drill requirements, persists state atomically, and exposes passport, commit, open, and drill-state endpoints.
Passport fixtures and behavioral coverage
tests/plugins/career/*
Expands metadata fixtures and tests badge thresholds, arrangement handling, genre normalization, idempotent state changes, validation, orphan filtering, and drill gating.

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

Possibly related PRs

  • got-feedBack/feedBack#907: Earlier Career backend changes in plugins/career/routes.py use the same song statistics and venue-pack functionality.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: a career passport backend with genre badges computed from stars.
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 feat/career-passports

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

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