Since #8 collapsed the Round trick mirror onto PlayState, contrai_core.trick.Trick has no
production consumers left. The only reference in any src/ tree is the re-export in
contrai_core/__init__.py. This issue is to decide whether it stays.
Where it stands
- Production: zero call sites. The engine stopped importing it; nothing else ever did.
- Tests: its own
packages/contrai-core/tests/test_trick.py, plus
packages/contrai-engine/tests/test_view/test_recap.py, where it is only a fixture convenience
(a builder for "a pile of plays" handed to a stub play state) rather than a real dependency.
- Exceptions:
TrickStateError is raised by TrickRecord.__new__ as well, so removing Trick
would not orphan it.
Every capability has a live equivalent
Trick offers |
Replacement |
| mutable, incremental 0–4 plays |
PlayState.current_trick → tuple[Play, ...] |
get_current_winner on a partial trick |
module-level current_winner(plays, trump_suit) — which get_current_winner only delegates to |
get_led_suit |
PlayObservation.led_suit / TrickRecord.led_suit |
get_cards / get_plays |
the tuple itself |
is_complete / __len__ |
len(plays) == 4 |
The one property only Trick has is being mutable and built up play by play — which is exactly
the shape #8 removed. The mirror existed because a mutable accumulator was kept in lock-step with an
immutable state, and it drifted: the running "Round pts" line sat a frame behind the play state.
The argument for keeping it
The scraper (#7) will materialize observed games into core objects, and it watches a live table play
by play, so an accumulator is a plausible fit. But even there the better shape looks like a plain
list[Play] closed into a TrickRecord at the boundary — what PlayState already does, and what
feeds the play state and supervised learning with no conversion step.
Proposal
Defer the decision to whenever #7's persistence schema lands: that is the moment Trick's only
hypothetical consumer either materializes or doesn't. Deleting it today is a breaking change to a
public core API for no functional gain; leaving it costs nothing but a docs caveat, which
docs/core/index.md and class_core.puml now carry.
If we do remove it
Roughly one self-contained commit:
- delete the class from
packages/contrai-core/src/contrai_core/trick.py and drop it from
__init__.py's imports and __all__;
- in
test_trick.py, drop the TestTrick* classes and keep TestTrickRecord* /
TestCurrentWinnerParity;
- re-point
test_view/test_recap.py's fixtures at Play tuples (test_view/test_trick.py already
works this way);
- refresh the
Trick box and note in class_core.puml, plus the trick.py row in
docs/core/index.md.
Since #8 collapsed the
Roundtrick mirror ontoPlayState,contrai_core.trick.Trickhas noproduction consumers left. The only reference in any
src/tree is the re-export incontrai_core/__init__.py. This issue is to decide whether it stays.Where it stands
packages/contrai-core/tests/test_trick.py, pluspackages/contrai-engine/tests/test_view/test_recap.py, where it is only a fixture convenience(a builder for "a pile of plays" handed to a stub play state) rather than a real dependency.
TrickStateErroris raised byTrickRecord.__new__as well, so removingTrickwould not orphan it.
Every capability has a live equivalent
TrickoffersPlayState.current_trick→tuple[Play, ...]get_current_winneron a partial trickcurrent_winner(plays, trump_suit)— whichget_current_winneronly delegates toget_led_suitPlayObservation.led_suit/TrickRecord.led_suitget_cards/get_playsis_complete/__len__len(plays) == 4The one property only
Trickhas is being mutable and built up play by play — which is exactlythe shape #8 removed. The mirror existed because a mutable accumulator was kept in lock-step with an
immutable state, and it drifted: the running "Round pts" line sat a frame behind the play state.
The argument for keeping it
The scraper (#7) will materialize observed games into core objects, and it watches a live table play
by play, so an accumulator is a plausible fit. But even there the better shape looks like a plain
list[Play]closed into aTrickRecordat the boundary — whatPlayStatealready does, and whatfeeds the play state and supervised learning with no conversion step.
Proposal
Defer the decision to whenever #7's persistence schema lands: that is the moment
Trick's onlyhypothetical consumer either materializes or doesn't. Deleting it today is a breaking change to a
public core API for no functional gain; leaving it costs nothing but a docs caveat, which
docs/core/index.mdandclass_core.pumlnow carry.If we do remove it
Roughly one self-contained commit:
packages/contrai-core/src/contrai_core/trick.pyand drop it from__init__.py's imports and__all__;test_trick.py, drop theTestTrick*classes and keepTestTrickRecord*/TestCurrentWinnerParity;test_view/test_recap.py's fixtures atPlaytuples (test_view/test_trick.pyalreadyworks this way);
Trickbox and note inclass_core.puml, plus thetrick.pyrow indocs/core/index.md.