Enhancement/update points to win with 3 and 4 kings, create new and u… - #207
Merged
Merged
Conversation
…pdate existing test case
itsalaidbacklife
approved these changes
Nov 8, 2022
itsalaidbacklife
left a comment
Contributor
There was a problem hiding this comment.
Looks good. My change requests are in the comments, and then we're ready to merge
itsalaidbacklife
added a commit
that referenced
this pull request
Aug 4, 2026
…dates Replace the flat '1.0.0' backfill with a CASE over each game's createdAt, mapping to the rule set live at that time using the UTC merge timestamps of the PRs that shipped each change: #207 (0.0.1), #855 (0.1.1), #1197 (1.0.0), #1320 (1.0.1). Still idempotent (ADD COLUMN IF NOT EXISTS + WHERE rulesVersion IS NULL). New games get 1.0.2 from the model default and are left untouched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
itsalaidbacklife
added a commit
that referenced
this pull request
Aug 4, 2026
itsalaidbacklife
added a commit
that referenced
this pull request
Aug 4, 2026
* feat: replace eager hand-limit enforcement with discard-to-hand-limit phase
Introduces a new DISCARDING_TO_HAND_LIMIT game phase (value 6) so players
can always draw or resolve moves that overflow the 8-card hand limit, then
discard down immediately rather than being blocked upfront.
- Draw: removed the block-at-8 validation; drawing a 9th card enters the
new phase instead of incrementing turn
- Five: always draws 3 cards (removed the spaceInHand cap); overflows
trigger the discard phase
- Nine: if the returned card pushes the targeted player over 8, they enter
the discard phase before getting their turn
- New discard-to-hand-limit validate/execute helpers; supports discarding
1 card (hand=9) or 2 cards (hand=10) in a single move
- Frontend: DiscardToHandLimitDialog, game store computed/action wiring,
socket event handler, and i18n strings
- AI: generates all valid discard combinations for the new move type
- Tests: updated basicMoves, 5_fives, and 9_nines specs; new handLimit.spec.js
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs(game-state-api.md): init
* refactor: switch to disardedCard in api for discarding to hand limit
* test: fix which player is p0 and handling of empty deck in hand limit tests
* fix(translations): match en.json for hand limit
* test(9_nines.spec.js): fix it('Nine returns card to player hand at hand limit, triggering discard dialog for player'
* fix(translations): add game.snackbar.oneOffs.discardToHandLimit key to each file
* refactor(DiscardToHandLimitDialog): switch to script setup
* docs(AGENTS.md): describe pinia and script setup
* refactor(inGameEvents): move discard to hand limit block into main handler
* fix(discard-to-hand-limit/validate): add turn check
* docs(translations/CLAUDE.md): init file to instruct maintaining lang file parity
* docs(translations/CLAUDE.md): revise copy
* fix: set phase and increment turn based on hand limit
* chore(.gitignore): allow AI config files
* docs(.clause/rules/translation-parity.md) pull into .claude/rules with paths spec
* test(9_nines.spec.js): adjusted hand limit cases to avoid dialog on same turn
* refactor(handLimit.spec.js): reorganize by move type
* fix(resolve/execute): set discard based on active player not playedBy
* test(handLimit.spec.js): add 'Forces player to discard down to hand limit after opponent nines and player draws'
* test(handLimit.spec.js): implement Skips discarding when opponent nines player at the hand limit and player then plays points
* chore(handLimit.spec): remove .only()
* test(handLimit.spec.js): add Discards down to hand limit after playing a 4 on opponent when player has 10 cards in hand
* fix(resolve-four/execute.js): make it the four-player to discard down to hand limit after four resolution
* chore(handLimit.spec.js): remove .only()
* fix(get-active-player-p-num): use turn/active player for DISCARDING_TO_HAND_LIMIT case
* fix(get-log.js): update log for discard to hand limit to accommodate multiple cards
* docs(game-state-api.md): fix typo
* fix(game.js): set waitingForOpponentToDiscard based on turn for discarding to hand limit case
* fix(game.js): set showDiscardToHandLimit based on turn + phase
* chore(translations): remove unused draw.handLimit keypair
* docs(game-state-api.md): Remove project-proposal/RFC language
* docs(game-state-api.md): document discarding to hand limit phase
* docs(game-state-api.md): remove 'can be null' since it's in the type def
* docs(game-state-api.md): format code blocks
* docs(game-state-api.md): doc the hand limit phase + move types
* docs(game-state-api.md): fix capitalization
* docs(game-state-api.md): doc game phase
* docs(game-state-api.md): pull docs for MoveType into own section
* docs(game-state-api.md): replace numbered lists with bulleted lists
* docs(game-state-api.md): update draw/execute example
* docs(game-state-api.md): Apply code review revisions
Co-authored-by: Ryan Emberling <itsalaidbacklife@gmail.com>
* fix(draw/validate): set activePlayer based on turn
Co-authored-by: Ryan Emberling <itsalaidbacklife@gmail.com>
* chore(basicMoves.spec.js): rename test case
* test(handLimit.spec.js): assert gameState more specifically
* refactor(discard-to-hand-limit/execute): simplify discard loop, keep presence guard
Address review feedback: splice once and push the removed card to both
discardedCards and scrap (dropping the double-read). Keep a lightweight
cardIndex === -1 guard so a validate bypass can never splice(-1) and silently
remove the wrong card.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(get-move-bodies-for-move-type): document discard combination bound
Address review feedback about the discard combination recursion. Document that
C(hand, overflow) is bounded by game rules (hand <= ~10, overflow 1-2), so there
is no blow-up risk. No behavior change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(handLimit.spec.js): add pass-over-hand-limit discard test
Add a Passing and Hand Limit case: with an empty deck and a 9-card hand, the
player passes (clicking the deck) and is forced into the discard-to-hand-limit
dialog, with the turn only advancing after discarding down to 8.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(rules): update hand limit text for end-of-turn discard
Reflect the reworked hand limit in the How To Play rules across all five
locales: the Play section now describes performing one action then discarding
down to 8, and the Draw and Five descriptions no longer claim you cannot exceed
the 8-card hand limit.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(Game): track rulesVersion of the rule set used per game
Add a canonical CURRENT_RULES_VERSION constant (utils/rulesVersion.js) and stamp
it onto each Game via a defaulted rulesVersion column, so any game can be
disambiguated back to the rules it was played under. The hand-limit rework is
version 1.0.0. Orthogonal rule mods (e.g. jokers) are intentionally deferred to
a future ruleVariants column.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(skills/announcement): add skill to author home-page announcements
Add an /announcement skill that gathers announcement copy, timing, and optional
image/cards, then produces the announcementData object and the flat announcement
i18n block across all five translation files, following the pattern of prior
announcement PRs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(announcement): announce the hand limit rework
Replace the site announcement with the hand-limit-rework notice: activator
"Hand Limit Rework", dialog title "Hand Limit", and copy explaining the
simplified single rule (discard down to 8 at end of turn) that replaces the
separate draw/Five/Nine hand-limit interactions. Open-ended (no time bounds) and
shown to all users; drops the now-unused twitchLink key across all five locales.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(e2e): suppress always-on announcement dialog before app load
The hand-limit announcement has no date window, so its dialog is always active
and its overlay scrim covered UI elements, failing many e2e specs. Seed
LS_ANNOUNCEMENT in the global window:before:load handler so the flag is present
before the app mounts (AnnouncementDialog reads localStorage synchronously at
mount, so dismissIntroPopups() after cy.visit is too late). Keeps the
announcement always-on in production while suppressing it in tests.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(migrations): add idempotent game.rulesVersion column migration
Production/staging run Waterline with migrate: 'safe', so the new Game.rulesVersion
column (PR #1359) is not auto-created and must be applied by hand. Add an idempotent
SQL migration that ADD COLUMN IF NOT EXISTS "rulesVersion" on "game" and backfills
existing rows to '1.0.0'. New rows get '1.0.0' from the model's defaultsTo.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(rulesVersion): bump to 1.0.2
* chore(rulesVersion): renumber and add 5 rework
* docs(rulesVersion): add rule set version history, bump current to 1.0.2
Document the full VERSION HISTORY (0.0.0 -> 1.0.2) and set CURRENT_RULES_VERSION
to 1.0.2 for the hand-limit rework, so new games are stamped 1.0.2 via the Game
model default.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(migrations): backfill rulesVersion by createdAt using PR merge dates
Replace the flat '1.0.0' backfill with a CASE over each game's createdAt, mapping
to the rule set live at that time using the UTC merge timestamps of the PRs that
shipped each change: #207 (0.0.1), #855 (0.1.1), #1197 (1.0.0), #1320 (1.0.1).
Still idempotent (ADD COLUMN IF NOT EXISTS + WHERE rulesVersion IS NULL). New
games get 1.0.2 from the model default and are left untouched.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(translations): translate discardToHandLimit dialog + snackbar keys
The game.dialogs.discardToHandLimit (title/body/discard) and
game.snackbar.oneOffs.discardToHandLimit (notDiscardingPhase/handNotOverLimit/
mustSelectCards) values were left as English placeholders in de/es/fr/ukr when
the keys were first added. Translate all six into each language, consistent with
each file's existing hand-limit terminology.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(translation-parity): require translated values, add placeholder self-check
Add a 'Values must be in the file's language' section forbidding English
placeholders in non-English files (the failure mode that left discardToHandLimit
untranslated), covering key *additions* not just value changes, plus a self-check
comparing non-English values against en.json. Cross-reference it from the
announcement skill.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(rulesVersion): reference the PR behind each version
Annotate the VERSION HISTORY with the PR that shipped each rule change (#207,
#855, #1197, #1320, #1359) after the initial version.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(skills): add game-state-api skill routing to the move-lifecycle doc
Add a skill that instructs when to read docs/game-state-api.md — before working
on game-move processing (MoveType changes, validate/execute helpers, the
move.js request lifecycle, GameState/GameStateRow packing, the card string
format, GamePhase/MoveType enums, models, or the socket payload).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(rules): replace cheatsheet PDF with v6, update cheatsheet link
Remove public/img/cuttle_rules.pdf, add public/img/cuttle_rules_v6.pdf (the _v6
suffix busts caches), and point the Cuttle Cheatsheet link in RulesView.vue at
the new path.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(rules): update cuttle_rules_v6 cheatsheet PDF
Replace public/img/cuttle_rules_v6.pdf with the revised version.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(skills/announcement): glob translation files instead of hardcoding the list
Reference src/translations/*.json (and 'every translation file') instead of the
explicit {en,de,es,fr,ukr} list / 'all five' phrasing, so adding a new locale
doesn't leave the skill stale.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore: remove migrations/ folder
Drop the standalone SQL migration for game.rulesVersion.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(e2e): seed play-time flag pre-load and remove dismissIntroPopups
The global window:before:load hook now seeds both LS_ANNOUNCEMENT and
LS_PLAY_TIME_DIALOG_DISMISSED before app load, suppressing both intro dialogs
uniformly. Delete the now-redundant dismissIntroPopups command (its LS_ANNOUNCEMENT
write ran after cy.visit, too late; its play-time write was inert since that
dialog only shows after 60s in a lobby) and all 19 call sites. The 'Lobby - Play
Time Dialog' block opts back in by clearing the play-time flag in its beforeEach
(enterLobby uses SPA nav, so no reload re-seeds it).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(rules): update cuttle_rules_v6 cheatsheet PDF
Replace public/img/cuttle_rules_v6.pdf with the latest cheatsheet iteration.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(DiscardToHandLimitDialog): select cards by id directly
Pass card.id from the template to selectCard instead of the hand index and
looking the id back up; drop the now-unused v-for index. No behavior change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
…pdate existing test case
Please check the following
Please describe additional details for testing this change