Skip to content

engine/core: unify the three trick-winner computation call paths #8

Description

@valmathieu

Problem

The trick-winner rule is computed through three independent call paths that all delegate to the same core current_winner free function (packages/contrai-core/src/contrai_core/trick.py):

  1. PlayState.trick_winners maps current_winner over completed_tricks (packages/contrai-core/src/contrai_core/play.py).
  2. Round recomputes the winner on its mutable mirror Trick (packages/contrai-engine/src/contrai_engine/model/round/round.py, get_current_winner on current_trick) — this is what feeds team_tricks and last_trick_winner for scoring.
  3. The view builds a throwaway proxy Trick and pushes directly onto proxy.plays to reuse the rule (packages/contrai-engine/src/contrai_engine/view/state_helpers.py, _current_winner).

They agree today because they share the underlying function, but three call sites independently asserting the same fact is redundancy waiting to drift — especially the view's proxy-object construction, which bypasses Trick's normal API.

Proposal

Unify on the core Play records / PlayState as the single source of truth:

  • Round reads winners from PlayState.trick_winners instead of recomputing on its mirror Trick.
  • The view's state_helpers._current_winner consumes the same plays-based rule directly (no proxy Trick).
  • Longer term this folds into reducing the Round mirror-state duplication (Trick holding (Player, Card) tuples vs core Play records).

Notes

  • Pure refactor: no behaviour change; existing round-lifecycle and view tests must stay green.
  • Good to schedule alongside or after the Position migration since both touch Round/view seams, but not blocked by it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions