khodowany 2759337d16 Setup
2026-10-04 21:15:21 -05:00
2026-10-04 17:27:45 -05:00
2026-10-04 21:15:21 -05:00
2026-10-04 21:15:21 -05:00
2026-10-04 21:15:21 -05:00
2026-10-04 21:15:21 -05:00
2026-10-04 21:15:21 -05:00
2026-10-04 21:15:21 -05:00
2026-10-04 21:15:21 -05:00
2026-10-04 21:15:21 -05:00
2026-10-04 21:15:21 -05:00
2026-10-04 17:27:45 -05:00
2026-10-04 17:27:45 -05:00
2026-10-04 21:15:21 -05:00

Fantasy Politics

product-fpol is a private, noncommercial fantasy politics game for friends around the 2026 US midterms. This first playable development slice lets you browse candidates, build a 12-slot party, check league capacity and replay fictional election-night scoring.

The backend is C++23, with Modulus for builds, Ligo for HTTP, and Noto/SQLite for immutable catalog, rating and results snapshots. The frontend is TypeScript/Vite. Accounts, live drafts, cross-team ownership, trades, automatic data ingestion and deployment are later milestones.

Start developing

Prerequisites: Linux, Docker available to your user, Python 3, and Node.js 22.12+ with npm (CI uses Node 24). Initial setup requires network access for public Conan packages, the build image and npm dependencies. Sibling library checkouts are not required.

python3 modulus.py configure
python3 modulus.py build

Seed the development database with explicitly fictional candidates, ratings and results. Run the built admin executable from the repo root in the build environment, or directly on a compatible Linux host:

build/build_x86_debug/fpol_admin import \
  data/demo/catalog.json data/demo/ratings.json \
  data/demo/results-0.json data/demo/results-1.json \
  data/demo/results-2.json data/demo/results-3.json data/demo/results-4.json

# Optional: a separate, partial real catalog. It has no real ratings/results.
build/build_x86_debug/fpol_admin import data/real/mi-2026-10-04.json

python3 modulus.py run

In another terminal:

cd frontend
npm ci
npm run dev

Open http://127.0.0.1:5173. Select the fictional catalog, click Try an example roster, then Play replay. Search/filter the field, change picks and compare points with/without race multipliers. Vite proxies /api to port 8080. Restart the backend after C++ changes; refresh the browser after imports. The roster is an in-page sandbox and is cleared on refresh or catalog change.

Data is stored at var/fpol.sqlite (ignored by Git), relative to the working directory. Both executables accept --database PATH; use the same path when importing and serving. Importing the same document again is harmless. Corrections require new snapshot IDs, preserving the earlier result for replay. python3 tools/generate_demo.py deterministically regenerates only fictional fixtures.

The standard Modulus runner launches fpol_server inside its container, publishes port 8080 only on host loopback, and mounts the repository so the development database persists. For local direct builds, launch the built server executable instead. There is no hosted environment or authentication yet.

Scoring to try

Every office — House, Senate, Governor — has a Democrat, Republican, Other and Flex slot. Other includes independent and third-party candidates; Flex takes any affiliation in that office. Each candidate can appear only once in a roster, and opposing candidates may both be picked.

(vote share percentage + 50 if called/certified winner) × frozen race multiplier

Rating Multiplier Example
Safe 1.00 80% winner → 130 points
Likely 1.10 60% winner → 121 points
Lean 1.25 54% winner → 130 points
Toss-up 1.50 51% winner → 151.5; 49% loser → 73.5

Candidates are rounded half up to two decimals before summing. Reporting shares score without a win bonus; the current-leader preview is hypothetical and displayed separately. A missing count/rating is unknown, never an invented zero. Only a filled, fully scored roster gets a complete total. Corrections can retract a call. The replay demonstrates unreported votes, early totals, changing leads, calls and corrections. All five frames are synthetic, not a historical backtest.

Admin and API

build/build_x86_debug/fpol_admin --help
build/build_x86_debug/fpol_admin capacity data/demo/capacity.json
build/build_x86_debug/fpol_admin score-preview data/demo/preview.json
build/build_x86_debug/fpol_admin catalog

The last three commands use the same C++ handlers as POST /api/capacity, POST /api/score-preview and GET /api/catalog. GET /api/rules describes the slots and scoring. GET /api/health is process liveness. Ligo returns { "ok": true, "payload": ... }, or an error envelope. No admin write endpoint is exposed.

See the data/API contract for schemas, immutable import behavior, input bounds and round handling. The capacity report checks the per-party and total candidate supply for 2–12 players; it does not certify ratings or results coverage.

Data readiness

The real league is not ready to draft. The included Michigan snapshot contains 73 candidates in 15 races; the remaining states, real ratings and live result/call coverage are unresolved. Switching to that catalog shows those gaps rather than fictional replacements. An official candidate list may change and must be reconciled before use.

Read the dated source feasibility report and office/state coverage matrix. Free automatic updates remain a launch requirement. No provider transport or national coverage is claimed verified, and no background scraper/poller has been enabled. Runoff/ranked-choice resolution also requires a settled policy before affected races can launch.

Serve the built frontend

npm --prefix frontend run build
python3 modulus.py run -- --web-root frontend/dist

Open http://127.0.0.1:8080. Assets load at startup, so restart after rebuilding. Node is not needed to serve built assets. The server accepts --host, --port, --web-root, --database and --help; defaults are 127.0.0.1:8080, API-only, and var/fpol.sqlite. Port 0 selects an available port. SIGINT/SIGTERM stop it cleanly. Exact registered static paths are served; hidden files, symlinks and /api asset collisions are excluded. Use only Vite output as the web root. npm --prefix frontend run preview is available on port 4173 with the same API proxy.

Verify changes

python3 modulus.py configure --all
python3 modulus.py build --all
python3 modulus.py test --all
python3 modulus.py format --check
npm --prefix frontend run build

CTest's product_fpol suite runs the domain/persistence tests through the production admin executable, then HTTP process tests for API envelopes, validation, static assets, startup errors, occupied ports and shutdown. The frontend build includes strict TypeScript checking. For socket-restricted environments, core checks can also run independently:

python3 tests/test_core.py build/build_x86_debug/fpol_admin

Passing core checks does not replace the HTTP suite. See the local verification record for the compiler and environmental limitations of this implementation session. CI retains the shared GCC 12 debug/release builds and full test suite.

Configure generates ignored editor support; customize modulus.json and refresh with python3 modulus.py lsp. C++ and Python follow shared Modulus formatting; run python3 modulus.py format before committing. The checked-in bootstrap remains byte-identical to Modulus's canonical bootstrap. configure --update refreshes tooling/packages; --no-remote needs an already-populated project cache. CMake installs both executables; distribute frontend assets separately.

Next milestone

Clear the data gates first. Then add the private league and invitations, persist team ownership, freeze the chosen catalog/ratings before a live snake draft, add trades/locks, and connect verified polling to the existing snapshot/import layer. Election-night standings can reuse the deterministic scorer and correction history. Keep product rules here and reusable infrastructure in the shared library repos.

S
Description
No description provided
Readme 212 KiB
Languages
C++ 49.5%
Python 21.6%
TypeScript 19.6%
CSS 5.1%
JavaScript 2.5%
Other 1.7%