Finding 1 of the 2026-07-29 security review: hosting bound 0.0.0.0 --
every interface -- with no password and no encryption, so anyone who
could reach the machine's port was handed a seat and the game state.
New defcustom cg-net-host-address defaults to 127.0.0.1; the wide-open
value remains available and its docstring says exactly what choosing it
means. This converts "anyone who can reach you" into "someone you
deliberately let in", and bounds Finding 4's unauthenticated
memory-exhaustion route to local callers along the way.
Test cgt-net-host-loopback-default checks both the default value and
the actual bound address (process-contact :local). Against the
previous code it fails with (void-variable cg-net-host-address); the
old bind, captured before the patch: [0 0 0 0 PORT].
Finding 2 of the 2026-07-29 security review (CONFIRMED there): text
properties survive the prin1/read round trip the protocol is built on,
so a malicious host could send a client strings whose properties rebind
keys or carry expressions evaluated during redisplay.
New cg-net--scrub walks a decoded message and passes every string
through substring-no-properties; conses and vectors are copied, shared
and circular structure is tolerated. It is applied inside
cg-net--filter -- the one decode point both the host and the client
read through -- so both directions are covered at the boundary rather
than at each use site.
Test cgt-net-strips-properties (loopback, both directions) fails
against the previous code with properties intact: value (keymap (keymap)).
Bump z per the releasable-set convention. Ship the Info manual
(make info; make info-emacs fallback). Generate README.md from
README.org via Emacs batch ox-md, with a pre-commit hook and
board screenshots.
Add build.el + pre-commit hook so README.org stays the source and
README.md is regenerated for GitHub/MELPA. Refresh README (screenshots,
Crapette, use-package, new customs). Makefile: readme/hooks/info-emacs
targets; ship README.md.
* doc/card-games.texi: write the Russian Bank (Crapette) chapter (shared
foundations and houses, loading, the "Stop" foundation-priority rule,
sequenced house moves, the difficulty dial), the Networked Play chapter
(cg-bid-host/cg-bid-join, the lobby, cg-bid-shuffle-partners), and the
Credits chapter. The manual now builds with no makeinfo warnings.
* doc/card-games.texi: write the Rummy Games (Gin, Rummy, Rummy 500, Hand
& Foot), Matching Games (Go Fish, Old Maid), Capturing Games (Scopa,
Casino), and Climbing Games (President, Spite & Malice) chapters, each
with object, rules, strategy, and keys; give Cribbage its own chapter
(it's a pegging game, not climbing) and add it to the top menu.
* doc/card-games.texi (Trick-Taking Games): shared-keys intro plus a
section for each game -- 500, Hearts, Spades, Whist, Oh Hell, Euchre,
Pitch, Briscola, and Contract Bridge -- with object, rules, a strategy
note, and its keys, including the distinct 500 and Bridge keymaps.
* doc/card-games.texi (Solitaire Games): shared-keys table plus a section
per game -- Klondike, FreeCell, Spider, Yukon, Canfield, Forty Thieves,
Scorpion, one-player Russian Bank, Golf, TriPeaks, Pyramid, Gaps
(Montana), and Hell's Half-Acre -- each with object, rules, a strategy
note, and its keys.
* doc/card-games.texi: fill in Introduction, Installation, The Game Menu,
Playing, and Customization with real text and @findex/@vindex indexing;
add sub-sections for installation and customization.
* doc/card-games.texi: new manual skeleton -- header, CC-BY-4.0 copying,
dir entry, title page, Top menu, stub chapters for every section, and the
index. Builds cleanly with makeinfo.
* Makefile (info, html, pdf, docclean): build the manual; add the source
to the package tarball.
* .gitignore: ignore the generated manual outputs.
* card-games.el (card-games-treatment, card-games--svg-card-vars,
card-games--full-svg-vars, card-games-set-treatment): switch all games
between UNICODE, SVG cards, and the full-window SVG table by toggling the
per-game display vars together. (card-game--cycle-treatment, card-game):
a clickable control in the chooser.
* test/card-games-tests.el: cgt-treatment-set.
* NEWS: note the treatment selector.
* cg-core.el (cg-ai-level): new difficulty defcustom. (cg-red-suit-p):
return a normalised boolean so two red suits compare equal by colour --
diamond and heart were wrongly treated as opposite colours, letting a red
card build on another red card in the alternating-colour games.
* cg-crapette.el (cg-crap--ai-greedy-move, cg-crap--ai-play): honour easy
/ normal / hard.
* cg-trick.el (cg-trick--run): easy plays a random legal card.
* card-games.el (card-game): clickable AI-level control.
(card-game--cycle-ai, card-games-set-ai-level): change it.
* test/card-games-tests.el: cgt-red-suit-boolean, cgt-ai-level-easy-crapette;
bind cg-ai-level in cgt-crap-ai-enabling.
* NEWS.
* cg-svg.el (cg-svg-card-back): default to random; add lattice/waves/diamond
and the emacs/emacs-classic/gnu/splash logo backs. (cg-svg--back-*,
cg-svg--draw-back): draw them. (cg-svg--card-backs, cg-svg--random-back,
cg-svg--roll-back, cg-svg-shuffle-card-back, cg-svg--effective-back): random
machinery.
* card-games.el (card-game): re-roll the random back on each menu visit.
* test/card-games-tests.el: add cgt-svg-logo-smoke, cgt-svg-card-back-smoke.
* NEWS: note the card backs and random default.
* cg-svg.el (cg-svg-emacs-logo): new defcustom. (cg-svg--logo-files,
cg-svg--logo-file, cg-svg--draw-logo-emblem, cg-svg-draw-logo): embed a real
Emacs logo image via svg-embed, with the drawn emblem as a fallback.
* cg-bid-ui.el (cg-bid--draw-logo): delegate to cg-svg-draw-logo.
* NEWS: note the switchable logo.
* cg-cribbage.el (cg-crib--svg, cg-crib--render-text): board with a peg-track,
the starter, the pegging count/cards, the crib, and the hand.
board with the rubber/contract, four seats with the dummy exposed, the trick,
and the interactive hand.
* test/card-games-tests.el: add cgt-crib-svg-smoke, cgt-bridge-svg-smoke.
* NEWS: note the boards; every game now has a full SVG board.
discard, suit in play, stock, and the hand.
* cg-spite.el (cg-spite--board-svg, cg-spite--render-text): centre piles,
goal, discards, and hand.
* cg-match.el (cg-om--svg, cg-om--render-text, cg-render-apply): Old Maid
board with clickable target cards; wire mouse-1, zoom, and cg-current-game.
* test/card-games-tests.el: add cgt-eights-svg-smoke, cgt-spite-svg-smoke,
cgt-om-svg-smoke.
* NEWS: note the new boards.
* cg-rummy.el (cg-rummy--board-svg): add :stock-label and a :discard 'none
books and your hand/foot.
* cg-scopa.el (cg-fish--svg, cg-fish--render-text): board with the table
* NEWS: note the new boards.
* cg-trick.el (cg-trick--svg, cg-trick--draw-backs): draw the whole table
as one SVG -- three opponents, the trick in a diamond, the South hand
fanned with cursor, legal-play hints, and pass marks; hand cards carry
(hand . INDEX) click regions. (cg-trick--render-text): the text fallback.
(cg-render): dispatch SVG on a graphical display, else text. Add a footer
legend; refresh the help. Covers Hearts, Spades, Whist, Oh Hell, and the
Euchre/Pitch/Briscola subclasses.
* test/card-games-tests.el: add cgt-trick-svg-smoke, cgt-trick-svg-bidding.
* NEWS: note the trick-taking SVG table.
* cg-trick.el (cg-trick--svg, cg-trick--draw-backs): draw the whole table
as one SVG -- three opponents, the trick in a diamond, the South hand
fanned with cursor, legal-play hints, and pass marks; hand cards carry
(hand . INDEX) click regions. (cg-trick--render-text): the text fallback.
(cg-render): dispatch SVG on a graphical display, else text. Add a footer
legend; refresh the help. Covers Hearts, Spades, Whist, Oh Hell, and the
Euchre/Pitch/Briscola subclasses.
* test/card-games-tests.el: add cgt-trick-svg-smoke, cgt-trick-svg-bidding.
* NEWS: note the trick-taking SVG table.
* cg-crapette.el (cg-crap--house-move): honour an optional WANT count on
an empty-house destination. (cg-crap--do-move): thread it through.
(cg-crap--hold-adjust, cg-crap-hold-less, cg-crap-hold-more): [ and ] set
the held count. (cg-crap--holding-line): show the run with the held
cards marked. (cg-crap-act): default the held count to the run length.
Bind [ and ]; update the legend and help.
* test/card-games-tests.el: add cgt-crap-sequence-partial, cgt-crap-partial-space.
* NEWS: note choosing the group size.
* cg-crapette.el (cg-crapette-stops): new defcustom.
(cg-crap--stop): call STOP (end your turn) or block, per the custom, when
you skip an available foundation play; wired into drop, draw, and end.
(cg-crap--builds-down-p, cg-crap--house-run, cg-crap--free-houses,
cg-crap--capacity, cg-crap--house-move, cg-crap--do-move): move a legal
sequence between houses, limited by the number of empty houses.
* test/card-games-tests.el: add cgt-crap-house-run, -sequence-move,
-sequence-space, -stop.
* NEWS: note the stop rule and sequenced moves.
* cg-crapette.el: new game on cg-core — eight foundations (up by suit,
two decks), eight shared houses (down, alternating colour), per-player
reserve/waste/hand; foundation priority; loading onto the opponent; a
greedy AI; text UI with cursor pick/drop, undo, and q-to-menu.
* card-games.el: require cg-crapette and add the chooser entry.
* Makefile (EL): add cg-crapette.el.
* test/card-games-tests.el: 5 ERT (deal, legality, win, AI turn, AI foundation).
Full-SVG 500 made mouse-operable for newcomers: kitty Discard button and
five-card cap, on-table phase banner, ? Help/Rules overlay with the bid
legend, legal-play dimming, card-size slider, and a layout pass that
moves the Help and size controls into the log panel so nothing overlaps.
Bump all files to 1.0.90, add NEWS, a README testing quick-start, and
make the shared engine files checkdoc-clean.
Full-SVG 500 made mouse-operable for newcomers: kitty Discard button and
five-card cap, on-table phase banner, ? Help/Rules overlay with the bid
legend, legal-play dimming, card-size slider, and a layout pass that
moves the Help and size controls into the log panel so nothing overlaps.
Bump all files to 1.0.90, add NEWS, a README testing quick-start, and
make the shared engine files checkdoc-clean.
The last three keyboard-only games are now click-to-play, so every game
in the package responds to the mouse.
Crazy Eights and President route their hands through the shared
cg-regions click map (President maps each rank group to a click); the
patience boards (Golf, TriPeaks, Pyramid) follow the solitaire keystone,
mapping exposed slots plus the waste and stock to their spots. Each adds
a card-size slider, [mouse-1], and +/-/0 zoom.
Add cgt-mouse-regions asserting the SVG click maps build (suite -> 116).
Rummy 500 gains the signature below-the-top discard pickup (T): take the
chosen card plus every card above it, melding or laying off the chosen
card at once. New `deep-pickup' class slot keeps Basic Rummy top-only;
the AI takes a buried card when it completes a new meld; the pile renders
with 0=top depth indices.
Hand & Foot gains its three missing rules: pick up the discard pile (p)
by melding the top card with two matching naturals; red threes as bonus
cards (auto-collected with a replacement draw, +100 each / +200 all four);
and the round-by-round go-down minimum (50/90/120/150) enforced as one
atomic initial meld.
Add four ERT tests (suite 111->115); refresh the README and in-file
commentary; fix cg-rum500.el's truncated file footer.
Extract the clickable hand+slider builder into cg-svg-hand-image and have
the rummy, trick, and bridge svg rows delegate to it. Tag the South hand
in cg-trick (covers all seven trick games) and the acting hand in
cg-bridge with click regions, mapping (hand . i) to select-and-play via
cg-render-apply; bind [mouse-1] and +/-/0. Suite 111/111.
Shared hand row gains a region-tag: tagged hands carry a cg-regions click
map (cards -> (hand . i)) and a card-size slider in the same image.
cg-core adds cg-mouse-action, cg-card-click, zoom commands, cg-card-scale
(folded into cg-scale), and a cg-render-apply base for scale/zoom. Seven
hand games are now click-to-position (Scopa/Casino/Spite click-to-play),
with [mouse-1] and +/-/0 bound. Adds cgt-hand-regions; suite 111/111.
cg-renderer gains a regions slot; the text/svg treatments get real
draw/hit methods; cg-regions-hit + cg-render-apply complete the loop.
Prototype on solitaire: cg-sol--svg returns (image . regions), redisplay
goes through cg-render-game, and [mouse-1] selects-and-acts by reusing the
keyboard pick-up/drop. Adds cgt-keystone-regions; suite 110/110.
Add SVG layouts so every game draws card faces on a graphical display:
- cg-solitaire: a board with the stock/waste/reserve/free-cells/foundations
row and overlapping columns (face-down backs, cursor ring, carried-run
hints) -- Klondike, FreeCell, Spider, Yukon, Canfield, Forty Thieves,
Scorpion.
- cg-patience: rows overlapped into the pyramid/peaks/Golf shapes with the
waste and stock -- Golf, TriPeaks, Pyramid.
- cg-eights: the hand as an SVG row with legal-play hints.
- cg-president: one face per rank with a count, keeping the rank-group cursor.
Each game keeps the plain-text row as the terminal/batch fallback behind a
cg-*-svg-cards toggle. Suite still 109/109.
Route cg-trick's shared render (the South hand and the current trick)
through cg-svg-hand-svg, showing legal plays as hint rings; this covers
Hearts, Spades, Whist, Oh Hell, Euchre, Pitch, and Briscola at once.
Do the same in cg-bridge for the hand, the trick, and the exposed dummy.
Plain-text rows remain the terminal/batch fallback. Suite still 109/109.
Add cg-svg-hand-svg, a hand-row primitive that fans a list of card
specs with cursor, hint, and mark rings, reusing the existing card art.
Route cg-rummy--render-cards through it on a graphical display, with the
plain-text row kept as the terminal/batch fallback (cg-rummy-svg-cards).
This gives SVG faces to every game that shares that helper: Gin, Rummy,
Rummy 500, Hand & Foot, Go Fish, Old Maid, Cribbage, Scopa, Casino, and
Spite & Malice. Suite still 109/109; batch rendering uses the text path.
New cg-bridge.el: a four-handed Bridge game (you are South, partnering
North against East and West) on the shared cg-game base.
* Auction: level/strain bids plus pass, double, and redouble, with the
three-pass end rule, pass-outs, doubling state, and declarer
determination (first of the side to name the strain).
* Play: follow-suit with the dummy exposed after the opening lead; the
declarer plays both hands. Trick resolution honours trump and no-trump.
* Scoring: classic rubber -- trick points below the line toward game;
overtricks, slam, insult, and undertrick penalties above; vulnerability
and the rubber bonus. Verified against known results.
* A small natural bidding AI (openings, NT, raises with a fit, simple
overcalls) that always terminates the auction, plus a greedy
card-play AI.
Wire cg-bridge into the chooser, the Makefile, and the README, and add
two ERT tests (scoring math and a dozen full AI-driven deals). The suite
is now 109/109 and every file byte-compiles cleanly.
Euchre, Pitch, Briscola, and Spite & Malice
Five new files, each reusing or extending an existing engine.
* cg-match.el: Go Fish and Old Maid, matching games on a shared
helper set (completes the original wishlist).
* cg-cribbage.el: two-handed Cribbage to 121 -- the crib, the cut,
pegging, and a full show scorer (fifteens, pairs, runs, flush, nobs).
* cg-scopa.el: a capture-by-sum engine driving Scopa (40-card, sette
bello, primiera, scopas) and Casino (pairs and sums, big/little
casino, aces, sweeps). Casino omits builds.
* cg-trick-ext.el: Euchre (24-card with both bowers), Auction Pitch
(bid, pitch sets trump, High/Low/Jack/Game), and Briscola (fixed
trump, no follow), as subclasses of the cg-trick engine.
* cg-spite.el: Spite & Malice, a competitive patience to empty the
goal pile onto shared Ace-to-Queen centre piles; Kings are wild.
Wire all nine commands into the card-game chooser, extend the Makefile
EL list, and add README sections. Add ten ERT tests covering each
game's engine and a full AI-driven game; the suite is now 107/107 and
every file byte-compiles cleanly.
New files at Version 1.0.60 to match the tree; post-1.0.60 work
toward 1.0.90.
Introduce a shared meld engine and four games built on it, all on
cg-core/EIEIO with console UNICODE rendering.
* cg-rummy.el: the meld engine and Gin Rummy. Set/run validation,
candidate-meld enumeration, a bitmask-DP minimum-deadwood partition,
and a layoff finder, plus the abstract cg-rummy-game base and shared
render helpers. Gin is two-handed with draw/take/discard/knock, gin
and undercut bonuses, opponent layoffs, and play to 100.
* cg-rum500.el: the abstract cg-tablemeld-game (one mode and command
set, dispatching on the subclass) driving Basic Rummy (meld out;
score the cards left in other hands; to 100) and Rummy 500 (score the
cards you lay down, lose those left in hand; ace high and worth 15;
to 500).
* cg-handfoot.el: Hand & Foot, a partnership Canasta cousin. Hand and
foot packets, Twos and Jokers wild, rank books with clean/dirty piles,
go-out bonus, and partnership scoring to 5000. Deliberately
Host-authoritative networked 500: host sits South, joiners take W/N/E,
open seats filled by AI. Per-seat rotated state hides other hands and the
kitty; clients reuse the single-player renderer/commands via :around advice,
so cg-bid.el/cg-bid-ui.el are untouched. Adds cg-bid-host/cg-bid-join, a
start-now lobby with auto-start at four players, and cg-bid-shuffle-partners.
cg-net.el gains cg-net-connect-functions. Verified: clean byte-compile,
checkdoc, 34/34 ERT (incl. 3 new net tests) and a two-process TCP game.