New tavolo-briscola distribution implementing briscola on the platform:
- pure rules (state.py, engine.py): 3-card deals, a face-up trump that
is the last card drawn, trump-first trick resolution (A > 3 > K > H >
J > 7 > 6 > 5 > 4 > 2), 120 points per deal, 60-60 patta re-deals, a
configurable target score (default 61), deal-end acknowledgements and
turn auto-play;
- BriscolaEngine (briscola, 2 players) and BriscolaQuattroEngine
(briscola_a_quattro, 4 players in fixed partnerships) adapters;
- registered in tavolo-app, packaged in the Docker image, documented.
Platform fixes surfaced by a two-player lobby:
- the websocket state and snapshot payloads now carry seats_open (they
were only in the REST lobby payload), so lobbies with player counts
other than four render correctly; seats_open is clamped at zero;
- the web client logs unparseable server messages instead of silently
dropping them.
Web client: briscola table for both variants (stock, face-up trump,
trick, last-trick banner), deal summary modal and game-over overlay.
Tests: tavolo-briscola rules/adapter suites, app integration tests
(lobby, websocket play, turn timeout, deal-end acks, persistence), a
platform seats_open test and frontend model parsing tests.
Builds the TracerProvider in tavolo.telemetry (kaya-otel's is private) and
injects it into kaya-otel, then instruments asyncpg and redis through
opentelemetry-instrumentation-asyncpg/redis. Redis command values are
redacted and asyncpg spans carry the parameterized SQL only.
Adds tavolo.active_users and tavolo.ongoing_games gauges, process/CPython
metrics via opentelemetry-instrumentation-system-metrics and OTLP log
export. The game store tracks ongoing matches (Redis sorted set, in-memory
set) and the session stores expose live counts for the gauges; a poller
refreshes them since metric callbacks cannot await the stores.
Relocate the composition root (app, config, static, logging_config,
aerich_config) from server/src/tavolo/ to
packages/tavolo-app/src/tavolo/, with its own pyproject.toml and README
like the sibling distributions. Module paths and the granian entrypoint
are unchanged.
server/pyproject.toml remains as a tooling shim ([tool.aerich] next to
./migrations, [tool.mypy] for runs from server/); the Dockerfile installs
all three distributions from ./packages. Verified: all suites green,
mypy clean per package, aerich resolves the moved config identically,
wheel builds.