Skip to content

feat(cardshed): attack + defense + phase transitions (M7+M8+M9) #152

@w7-mgfcode

Description

@w7-mgfcode

Sub-issue of #146. PRP 3 milestones M7 (AttackSelect / S05) + M8 (DefenseSelect / S06) + M9 (Phase transitions + TurnState wiring). Reference: `PRPs/cardshed-03-experience-prp.md` lines 844–913.

Scope

M7 — AttackSelect

  • `docs/SCREENS/attack-select.md` (Stitch)
  • `apps/ui/src/features/table/AttackSelect.tsx` — uses `getLegalActions(state, attackerId)` to highlight playable cards; selecting calls `validateAttack(selected, hand)` to enable/disable Send
  • Dispatch `{ kind: "Attack", playerId, cardIds }`

M8 — DefenseSelect

  • `docs/SCREENS/defense-select.md` (Stitch)
  • `apps/ui/src/features/table/DefenseSelect.tsx` + `components/{PendingAttackPanel,BeatPairButton}.tsx`
  • For each unbeaten attack, on hover highlight counter cards where `canBeat(attack, counter, trump) === true`
  • Dispatch `{ kind: "Beat", ... }` and `{ kind: "Stop", ... }` (with confirm when partial)

M9 — Phase transitions

  • `apps/ui/src/components/PhaseTransitionOverlay.tsx` — render the 6 `TurnState` values with distinct affordances; aria-live polite for screen readers

Acceptance

  • `Skill: stitch-design` → both screens committed
  • AttackSelect: 0/2/4/6 cards → Send disabled with `ATTACK_INVALID_SIZE` tooltip
  • AttackSelect: 3 = pair+kicker → Send enabled; 5 with quad → DISABLED with `ATTACK_NO_TWO_PAIRS`
  • Rejection messages quote core's `ValidationError.code` verbatim — no re-implementation of `validateAttack`
  • DefenseSelect: counter that can't beat → `BEAT_ILLEGAL` disabled state
  • Stop button shows Radix Tooltip + requires confirm when `unbeatenCards.length > 0`
  • After all beats, phase → `Resolving` and Stop is promoted (counter-attack hint) — see contradiction T10 — Catalog UI + detail view + MCP + E2E dogfood #10
  • PhaseTransitionOverlay renders `Dealing → AwaitingAttack → AwaitingDefense → Resolving → RoundEnded → MatchEnded` distinctly
  • aria-live polite announcements for every transition
  • `agent-browser` captures `dogfood-output//{m7-attack,m8-defense,m9-phases}/`

Common bugs (from PRP 3)

  • Re-implementing `validateAttack` or `canBeat` in the UI (FORBIDDEN — import + call)
  • Submitting on Enter without explicit confirm — allow mis-clicks
  • Allowing Stop without confirm at partial-defence point — destructive
  • Missing the `Resolving` branch (contradiction T10 — Catalog UI + detail view + MCP + E2E dogfood #10)
  • Blocking input during transition without a timeout — soft-lock risk

Complexity

M + M + S = ~10–15 hours.

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