Skip to content

fix(fleet): support selector rules and disambiguate same-name ships#419

Closed
yltx wants to merge 7 commits intomainfrom
fix/fleet-rules-search-name-disambiguation
Closed

fix(fleet): support selector rules and disambiguate same-name ships#419
yltx wants to merge 7 commits intomainfrom
fix/fleet-rules-search-name-disambiguation

Conversation

@yltx
Copy link
Copy Markdown
Contributor

@yltx yltx commented Apr 12, 2026

Summary

  • add FleetRuleRequest and plan.fleet_rules support in task schemas/routes
  • propagate fleet_rules through normal/event fight ops and preparation flow
  • enhance fleet change algorithm with selector-aware matching, refill, and occupied-slot handling
  • support search_name in choose-ship flow to disambiguate same-name ships (e.g. 大淀 variants)
  • bump package version to 2.1.9.post5

Why

Frontend now sends slot-level fleet selector rules (candidates/search_name). Without backend support, same-name ships can be treated as already matched and fail to replace, causing repeated fleet setup failures.

Validation

  • local static check on modified files passed
  • branch pushed and ready for review

Copilot AI review requested due to automatic review settings April 12, 2026 02:09
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds backend support for slot-level fleet selector rules (candidates/search_name/level range) and updates the UI fleet-change flow to better handle same-name ship scenarios by using selector-aware matching and optional search keywords.

Changes:

  • Introduce FleetRuleRequest and fleet_rules in task request schemas and propagate them through task execution and ops runners.
  • Enhance fleet-change logic to be selector-aware (candidate reuse, one-to-one matching, refill handling) and pass selector info down into the choose-ship UI flow.
  • Extend ship list OCR utilities to optionally keep duplicate ship-name rows and provide a row_key to correlate name hits with level OCR.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
autowsgr/ui/utils/ship_list.py Adds optional dedup control and row_key to support same-name rows and level correlation.
autowsgr/ui/choose_ship_page.py Adds selector-aware ship selection (candidates/search_name/min/max level) and returns matched ship name.
autowsgr/ui/battle/fleet_change/_change.py Updates fleet-change algorithm to consume selector rules and propagate them to UI selection.
autowsgr/server/schemas.py Adds FleetRuleRequest and fleet_rules to CombatPlanRequest.
autowsgr/server/routes/task.py Propagates fleet_rules overrides into normal/event fight task execution.
autowsgr/ops/normal_fight.py Adds fleet_rules support and prefers it over fleet during preparation.
autowsgr/ops/event_fight.py Adds fleet_rules support and prefers it over fleet during preparation.
autowsgr/init.py Bumps package version to 2.1.9.post5.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +363 to +380
"""为槽位挑选一个“未被当前编队占用”的候选舰船。"""
if name is None:
return None, None

candidates = cls._slot_candidates(name, selector)
occupied = {
ship for idx, ship in enumerate(current) if ship is not None and idx != slot_to_replace
}
available = [candidate for candidate in candidates if candidate not in occupied]
if len(available) == 0:
return None, None

chosen = available[0]
if selector is None:
return chosen, None

narrowed_selector = dict(selector)
narrowed_selector['candidates'] = available
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

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

_select_available_candidate() builds an occupied set of ship names and filters out any candidate already present elsewhere in the fleet. This makes it impossible to intentionally field duplicate ship names (same ship name appearing in multiple slots), even though the API accepts repeated names and the whole PR aims to handle same-name cases. Consider tracking occupancy by slot/instance (e.g., counts per name vs. required count, or allowing duplicates and only avoiding selecting the exact same slot), rather than treating a name as globally unique.

Suggested change
"""为槽位挑选一个“未被当前编队占用”的候选舰船。"""
if name is None:
return None, None
candidates = cls._slot_candidates(name, selector)
occupied = {
ship for idx, ship in enumerate(current) if ship is not None and idx != slot_to_replace
}
available = [candidate for candidate in candidates if candidate not in occupied]
if len(available) == 0:
return None, None
chosen = available[0]
if selector is None:
return chosen, None
narrowed_selector = dict(selector)
narrowed_selector['candidates'] = available
"""为槽位挑选一个候选舰船,不按舰名排除同名舰。"""
if name is None:
return None, None
candidates = cls._slot_candidates(name, selector)
if len(candidates) == 0:
return None, None
chosen = candidates[0]
if selector is None:
return chosen, None
narrowed_selector = dict(selector)
narrowed_selector['candidates'] = candidates

Copilot uses AI. Check for mistakes.
Comment thread autowsgr/server/schemas.py Outdated
Comment on lines +72 to +76
candidates: list[str] = Field(default_factory=list, description='候选舰船名(按优先级)')
search_name: str | None = Field(default=None, description='选船搜索关键词(用于同名舰船区分)')
min_level: int | None = Field(default=None, ge=1, description='等级下限(含)')
max_level: int | None = Field(default=None, ge=1, description='等级上限(含)')

Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

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

FleetRuleRequest.candidates defaults to an empty list, which allows a rules object that can't actually select anything; downstream _extract_selector() treats empty candidates as "no selector" and the slot effectively becomes None. If candidates are required for a rule, consider validating candidates as non-empty (e.g., min_length=1 / Field(..., min_length=1) or a model_validator that rejects empty lists) to fail fast on malformed requests.

Copilot uses AI. Check for mistakes.
Comment thread autowsgr/ops/normal_fight.py Outdated
Comment on lines +362 to +366
ship_names = (
self._primary_names_from_rules(self._fleet_rules)
if self._fleet_rules is not None
else self._fleet
)
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

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

When fleet_rules are used, _primary_names_from_rules() always picks the first candidate per slot, but the UI selection may fall back to a later candidate (or a different match) at runtime. This can cause self._fleet_ships (and thus result/context reporting) to record incorrect ship names. Consider deriving ship_names from the actual post-change fleet (e.g., page.detect_fleet() after change_fleet()), or have change_fleet() return the final resolved names.

Suggested change
ship_names = (
self._primary_names_from_rules(self._fleet_rules)
if self._fleet_rules is not None
else self._fleet
)
# 舰名以实际换船后的页面检测结果为准,避免规则匹配的首选候选与 UI
# 运行时实际选择不一致,导致上下文/结果记录错误。
ship_names = page.detect_fleet()
if not ship_names:
ship_names = (
self._primary_names_from_rules(self._fleet_rules)
if self._fleet_rules is not None
else self._fleet
)

Copilot uses AI. Check for mistakes.
Comment thread autowsgr/ops/event_fight.py Outdated
Comment on lines +285 to +289
self._primary_names_from_rules(self._fleet_rules)
if self._fleet_rules is not None
else self._fleet
)
self._fleet_ships = fleet_info.to_ships(ship_names)
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

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

When fleet_rules are provided, _primary_names_from_rules() uses only the first candidate per slot, which may not be the ship that was actually selected. This can make self._fleet_ships inaccurate in results/context. Prefer populating ship names from the real fleet after change_fleet() (e.g., page.detect_fleet()), or return resolved names from change_fleet().

Copilot uses AI. Check for mistakes.
@yltx
Copy link
Copy Markdown
Contributor Author

yltx commented Apr 12, 2026

Closing to recreate PR with same base/head.

@yltx yltx closed this Apr 12, 2026
veadex added a commit that referenced this pull request Apr 13, 2026
…420)

* fix(fleet): support fleet_rules selectors and disambiguate same-name ships

* chore(release): bump autowsgr to 2.1.9.post5

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix(review): address Copilot feedback for fleet rules

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix(review): address new Copilot comments on PR #419

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: X-vedeax <65024689+veadex@users.noreply.github.com>
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.

2 participants