diff --git a/.beans/nuzlocke-tracker-fv7w--add-team-size-limit-rule.md b/.beans/nuzlocke-tracker-fv7w--add-team-size-limit-rule.md
index 2656421..aeb81eb 100644
--- a/.beans/nuzlocke-tracker-fv7w--add-team-size-limit-rule.md
+++ b/.beans/nuzlocke-tracker-fv7w--add-team-size-limit-rule.md
@@ -1,33 +1,29 @@
---
# nuzlocke-tracker-fv7w
-title: Add team size limit rule
-status: todo
+title: Add boss team match rule
+status: in-progress
type: feature
priority: normal
created_at: 2026-02-20T19:56:22Z
-updated_at: 2026-02-20T20:01:53Z
+updated_at: 2026-02-20T21:01:36Z
parent: nuzlocke-tracker-49xj
---
-Cap the active party size with warnings when the limit is exceeded.
+When enabled, hint to the player that they should limit their active party to the same number of Pokemon as the next boss fight. This is a self-imposed difficulty rule — the tracker cannot enforce it since it doesn't track the active party, but it can surface the information.
-## Design Decisions
+## Design
-**Configurable limit:** Add `teamSizeLimit: number | null` to `NuzlockeRules`. `null` means no limit (disabled). Default Pokemon party size is 6, but variants like "trio-locke" use 3.
+**Rule:** Add `bossTeamMatch: boolean` to `NuzlockeRules` (default: `false`, category: `playstyle`).
-**What counts:** "Active team" = encounters with status `caught` and not fainted. The tracker already tracks this — alive Pokemon are shown in the team section on RunEncounters.
+**Display:** When enabled and the sticky boss banner is shown, add a hint next to the boss name showing their team size, e.g. "Next: Brock (2 Pokemon — match their team)". This reuses the existing `nextBoss` and its `pokemon` array.
-**No PC box tracking:** The tracker doesn't model a PC box. Excess catches beyond the team limit are still logged normally. The tracker just warns that the team is over capacity.
+**Variant bosses:** Some bosses have conditional teams (e.g. rival starter choice). Use the same logic as `BossTeamPreview`: count pokemon without a `conditionLabel` plus those matching the auto-detected variant (via `matchVariant`). Falls back to first variant if no match is detected.
-**Enforcement:** Soft enforcement. Show a warning banner on the encounters page when alive count exceeds the limit. Highlight the count in the team section header. Don't block new catches.
-
-**UI:** Add a numeric input to `RulesConfiguration` (shown when team size toggle is on, min 1, max 6). Display the limit in the sticky bar alongside level caps if enabled.
+**Scope:** Frontend-only. No backend or data model changes needed.
## Checklist
-- [ ] Add `teamSizeLimit: number | null` to `NuzlockeRules` interface (default: `null`)
-- [ ] Add `RuleDefinition` entry under `'difficulty'` category
-- [ ] Add numeric input to `RulesConfiguration` (shown when enabled, min 1, max 6)
-- [ ] Show warning banner on RunEncounters when alive team count exceeds limit
-- [ ] Display team size limit in sticky bar alongside level caps
-- [ ] Show count in team section header (e.g., "Team (4/3)" in red when over)
\ No newline at end of file
+- [x] Add `bossTeamMatch: boolean` to `NuzlockeRules` interface and `DEFAULT_RULES` (default: false)
+- [x] Add `RuleDefinition` entry (category: `playstyle`)
+- [x] Show boss team size hint in the sticky level cap banner when the rule is enabled
+- [x] Handle variant boss teams (use auto-matched variant count when available)
\ No newline at end of file
diff --git a/.beans/nuzlocke-tracker-sij8--add-gift-clause-rule.md b/.beans/nuzlocke-tracker-sij8--add-gift-clause-rule.md
index 4c13503..418af54 100644
--- a/.beans/nuzlocke-tracker-sij8--add-gift-clause-rule.md
+++ b/.beans/nuzlocke-tracker-sij8--add-gift-clause-rule.md
@@ -1,11 +1,11 @@
---
# nuzlocke-tracker-sij8
title: Add gift clause rule
-status: in-progress
+status: completed
type: feature
priority: normal
created_at: 2026-02-20T19:56:10Z
-updated_at: 2026-02-20T20:53:15Z
+updated_at: 2026-02-20T20:55:23Z
parent: nuzlocke-tracker-49xj
---
diff --git a/backend/src/app/seeds/inject_test_data.py b/backend/src/app/seeds/inject_test_data.py
index 07c3f46..25c1693 100644
--- a/backend/src/app/seeds/inject_test_data.py
+++ b/backend/src/app/seeds/inject_test_data.py
@@ -149,6 +149,7 @@ DEFAULT_RULES = {
"levelCaps": False,
"hardcoreMode": False,
"setModeOnly": False,
+ "bossTeamMatch": False,
"egglocke": False,
"wonderlocke": False,
"randomizer": False,
diff --git a/frontend/src/pages/RunEncounters.tsx b/frontend/src/pages/RunEncounters.tsx
index 86daa3c..3068893 100644
--- a/frontend/src/pages/RunEncounters.tsx
+++ b/frontend/src/pages/RunEncounters.tsx
@@ -178,6 +178,17 @@ function matchVariant(labels: string[], starterName?: string | null): string | n
return matches.length === 1 ? (matches[0] ?? null) : null
}
+/** Count boss pokemon for the effective variant (or all if no variants). */
+function getBossTeamSize(pokemon: BossPokemon[], starterName?: string | null): number {
+ const labels = [
+ ...new Set(pokemon.filter((bp) => bp.conditionLabel).map((bp) => bp.conditionLabel!)),
+ ]
+ if (labels.length === 0) return pokemon.length
+ const matched = matchVariant(labels, starterName)
+ const variant = matched ?? labels[0] ?? null
+ return pokemon.filter((bp) => bp.conditionLabel === variant || bp.conditionLabel === null).length
+}
+
function BossTeamPreview({
pokemon,
starterName,
@@ -1060,7 +1071,15 @@ export function RunEncounters() {
Level Cap: {currentLevelCap ?? '—'}
{nextBoss && (
- Next: {nextBoss.name}
+
+ Next: {nextBoss.name}
+ {run.rules?.bossTeamMatch && (
+
+ {' '}
+ ({getBossTeamSize(nextBoss.pokemon, starterName)} Pokémon — match their team)
+
+ )}
+
)}
{!nextBoss && (
All bosses defeated!
diff --git a/frontend/src/types/rules.ts b/frontend/src/types/rules.ts
index 84e5c96..bee3cd8 100644
--- a/frontend/src/types/rules.ts
+++ b/frontend/src/types/rules.ts
@@ -9,6 +9,7 @@ export interface NuzlockeRules {
// Playstyle (informational, for stats/categorization)
hardcoreMode: boolean
setModeOnly: boolean
+ bossTeamMatch: boolean
// Variant (changes which Pokemon can appear)
egglocke: boolean
@@ -27,6 +28,7 @@ export const DEFAULT_RULES: NuzlockeRules = {
// Playstyle - off by default
hardcoreMode: false,
setModeOnly: false,
+ bossTeamMatch: false,
// Variant - off by default
egglocke: false,
@@ -93,6 +95,13 @@ export const RULE_DEFINITIONS: RuleDefinition[] = [
'The game must be played in "Set" battle style, meaning you cannot switch Pokémon after knocking out an opponent.',
category: 'playstyle',
},
+ {
+ key: 'bossTeamMatch',
+ name: 'Boss Team Match',
+ description:
+ 'Limit your active party to the same number of Pokémon as the boss you are challenging.',
+ category: 'playstyle',
+ },
// Variant
{