Game Features
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
# Application API
|
||||
|
||||
All application responses are JSON `{ "ok": true, "status": 200, "payload": ... }`, or `{ "ok": false, "status": ..., "code": ..., "message": ... }`. The HTTP status agrees with the application status. Health and legacy simulator routes keep Ligo's original envelope. Player APIs return current projections; the development simulator alone exposes snapshot history.
|
||||
|
||||
## Authentication
|
||||
|
||||
`fpol_session` is a random opaque cookie, HttpOnly, SameSite=Lax, Path=/, with a 30-day lifetime. Only its SHA-256 digest is stored. Production requires `--secure-cookies` and an HTTPS `--origin`. Tokens never appear in HTTP JSON. Every POST needs `Origin` exactly matching `--origin` and `X-Fpol-Request: 1`; authenticated POSTs also need `X-CSRF-Token` from login or `GET /api/auth/me`. There is no cross-origin API/CORS access.
|
||||
|
||||
- `POST /api/auth/login`: `username, password`. Returns the user (`id, username, admin, csrf`) and sets the cookie.
|
||||
- `POST /api/auth/register`: `username, password, invite, team_name`. A valid invitation and available seat are checked again transactionally after hashing; a failed join does not create an orphan account.
|
||||
- `GET /api/auth/me`: current user and CSRF token.
|
||||
- `POST /api/auth/logout`: invalidates the session and clears the cookie.
|
||||
- `POST /api/auth/password`: `current_password, password`. Rotates all sessions, returning a new one.
|
||||
- `POST /api/auth/reset`: `reset_token, password`. Single-use operator token; revokes all sessions and reset tokens for that account. Sign in afterward.
|
||||
|
||||
Usernames have 3–32 ASCII letters, numbers or underscores, case-insensitive. Passwords have 12–256 UTF-8 bytes. Hashes use OpenSSL scrypt N=131072/r=8/p=1, an independent 128-bit salt, and a 512-bit result. Two hashing workers serve at most eight in-flight jobs, off the HTTP loop. Login attempts are transactionally limited to 10 per username and 100 per transport peer in 15 minutes; behind Caddy that peer allowance is shared by all players. Password recovery is CLI-only, with a 30-minute expiry. Database files/backups contain secrets and need private storage.
|
||||
|
||||
## Leagues
|
||||
|
||||
All routes require a session. League-scoped reads and writes require membership. An administrator has no implicit access to other players' leagues.
|
||||
|
||||
| Method / path | Input |
|
||||
| --- | --- |
|
||||
| GET `leagues` | none; lists own memberships |
|
||||
| POST `league/create` | `name, team_name, max_teams`; optional `catalog_id` (latest real catalog by default) |
|
||||
| POST `league/join` | `invite, team_name` |
|
||||
| GET `league` | query `league_id`; includes own queue, teams, picks, timer, readiness and recent events |
|
||||
| POST `team/name` | `league_id, name` |
|
||||
| POST `league/invite` | commissioner; `league_id`; returns a seven-day bearer invitation; replaces prior invitation |
|
||||
| POST `league/revoke-invites` | commissioner; `league_id` |
|
||||
| POST `league/remove` | commissioner; `league_id, team_id`; before draft only; also revokes existing invitations |
|
||||
| POST `league/name` | commissioner; `league_id, name`; rename without changing frozen rules |
|
||||
| POST `league/ratings` | commissioner; `league_id, document`; immutable sourced ratings JSON while forming |
|
||||
| POST `league/settings` | commissioner; `league_id, name, catalog_id, ratings_id` (nullable); before draft only; clears queues |
|
||||
|
||||
No public registration, public league directory, or email invitation service exists. An invitation is reusable until the league fills, it expires, it is revoked, or drafting starts. One account owns at most one team per league. The commissioner cannot remove their own team.
|
||||
|
||||
## Drafts
|
||||
|
||||
- `POST draft/start`, `draft/pause`, `draft/resume`: commissioner, `league_id`.
|
||||
- `POST draft/queue`: `league_id, candidates` (ordered unique candidate IDs, maximum 200). Other members never receive this queue.
|
||||
- `POST draft/pick`: `league_id, candidate_id, pick_number, request_id`. Use a unique request ID per attempted pick. Retrying the same body/ID returns the original pick; reusing an ID for another body fails with 409. Candidate and slot exclusivity are database constraints. The draft clock and human picks use the same serialized, transactional path; a pick at or after deadline fails and the timer advances the turn.
|
||||
|
||||
The draft starts only with 2+ teams, enough global/per-party supply, ratings for every race, and a complete national catalog plus enabled verified count/outcome coverage for real races. The compiled inventory includes 435 House seats, 35 Senate contests (including FL/OH specials), and 36 governor races. The practice pool bypasses real-data gates only under `--allow-demo`.
|
||||
|
||||
## Candidates and standings
|
||||
|
||||
- `GET catalogs`: catalog/rating summaries, no snapshot history. Demo summaries require `--allow-demo`.
|
||||
- `GET candidates`: optional `league_id` (pins frozen catalog/ratings/ownership), `catalog_id`, `search`, `office`, `state`, `affiliation`, `available=true`, `offset`, `limit` (1–100). `items` includes source provenance and rating/owner when applicable.
|
||||
- `GET results`: optional `league_id` or `catalog_id`; current race counts and separate outcomes. Includes received/source/check timestamps and stale status. No observations are invented for missing races.
|
||||
- `GET standings`: required `league_id`; team rosters, candidate score components, known subtotal, full total only when all 12 scores are known, reporting coverage, provisional flag, and tied competition ranks. Teams with no known scores are unranked.
|
||||
- `GET admin/sources`: administrator only; current source health, assigned coverage, 50 recent quarantines.
|
||||
|
||||
GET parameters are percent-decoded, `+` becomes a space, and duplicate/malformed parameters are rejected by the opted-in Ligo query parser. HTTP requests are capped at 64 KiB. There is no remote admin import/reset/SQL endpoint. `fpol_admin app-request FILE|-` is a **trusted local test/operator interface** that may return session secrets and accepts an injected clock; it is never an HTTP route.
|
||||
|
||||
## Persistence
|
||||
|
||||
Migration `001_documents` stays unchanged. `002_leagues` adds accounts, sessions, invites, leagues, teams, draft clocks, picks, idempotency commands, events, source configuration, raw payloads, observations, current projections, coverage and quarantine. SQLite WAL, foreign keys and a busy timeout are enabled. One application DB worker owns each short `BEGIN IMMEDIATE` transaction. Hashing and network polling happen outside these transactions. The ingestion process uses its own connection to the same volume.
|
||||
@@ -61,3 +61,9 @@ All responses use Ligo's `{ok: true, payload: ...}` or `{ok: false, code, messag
|
||||
| `POST /api/score-preview` | `{catalog_id, ratings_id, results_id, roster: [{slot, candidate_id}]}` | Validation, breakdown, baseline and leader preview |
|
||||
|
||||
The complete document response is intentionally suitable for this small prototype; pagination/indexed views will be needed as real replay history grows. Exact routes have no query-string normalization; the browser filters locally. Imported data becomes visible on the next request without restarting. The browser loads its catalog snapshot on page load; refresh after imports. No authentication is implemented yet; use local development until the multiplayer access controls exist.
|
||||
|
||||
## Compatibility with league scoring
|
||||
|
||||
The APIs and immutable documents above are the original **v1 development simulator**. Their `pending_round` preview behavior remains unchanged for replay compatibility. They are available over HTTP only with `--allow-demo`; CLI imports/previews remain available to the local operator.
|
||||
|
||||
Private leagues use the [application API](application-api.md) and separate [count/outcome observations](ingestion.md). Their frozen rule version is `v2-november-share`: November first-round/first-choice share continues to score during a pending runoff, and only the eventual winner bonus follows later-round outcomes. Do not use a v1 preview total as a v2 league standing. Commissioners can import a sourced ratings document through `POST /api/league/ratings` while a league is forming; it uses the existing immutable ratings schema and must reference that league's selected catalog.
|
||||
|
||||
@@ -43,3 +43,9 @@ The fictional catalog supports every allowed league size. Michigan alone cannot
|
||||
5. Settle runoff and ranked-choice scoring policy. The current importer rejects a different round for the same catalog race and `pending_round` remains unscored. A later round must not be added to an earlier count. Do not launch affected races until provider semantics and final-round handling are specified and tested.
|
||||
|
||||
Commissioner JSON imports make the foundation reviewable; they are not the planned election-night automation. If free sources cannot meet these gates, bring that concrete limitation back for a product decision rather than introducing a paid dependency or silently narrowing the game.
|
||||
|
||||
## League milestone update — October 4, 2026
|
||||
|
||||
The combined `data/real/us-2026-10-04-partial.json` now includes **115 candidates / 30 contests**: Michigan's existing 73/15 plus North Carolina's 42 candidates across 14 House districts and one Senate contest. NC facts were reviewed from [the official state-only November candidate list](https://s3.amazonaws.com/dl.ncsbe.gov/Elections/2026/Candidate%20Filing/2026_general_candidate_list_by_contest_federal_and_state.pdf), pages 1–3, report dated September 21. No residential/contact details were copied. Retrieval timestamps have day precision; midnight is a date placeholder. The remaining 48 states still need candidate imports; real ratings and live coverage remain incomplete.
|
||||
|
||||
A national inventory now records 506 scheduled November contests (435 House, 35 Senate including the FL/OH specials, 36 governor). It supplements the 150-row state/office matrix and guards draft readiness. Candidate source watches, Open America normalization, and a reviewed official JSON integration contract are implemented, but **no provider capture is verified**. civicAPI remains capture-only pending an actual response contract. See [ingestion](ingestion.md) for activation requirements and the settled November first-choice share policy.
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
# Hosting, backup and recovery
|
||||
|
||||
The repository contains a deployment configuration; no host has been selected or deployed. HTTP/browser/container tests must pass on a normal host before using it with friends. Real drafting remains data-gated separately.
|
||||
|
||||
## Build and bootstrap
|
||||
|
||||
Keep `product-fpol`, `modulus`, `noto`, and the updated `ligo` repositories beside each other. Compose uses the parent directory as its build context, excludes caches/secrets, exports those local Conan recipes, and builds a release C++ image with GCC 12. The frontend uses a separate Node build stage. First build requires internet access for base images and dependencies.
|
||||
|
||||
```sh
|
||||
cp .env.example .env
|
||||
# Set FPOL_DOMAIN to a hostname whose DNS points at your host; no scheme/path.
|
||||
docker compose build
|
||||
# Bootstrap migrations, the partial catalog, and an administrator before serving.
|
||||
docker compose run --rm --no-deps app fpol_admin --database /data/fpol.sqlite \
|
||||
import /app/data/real/us-2026-10-04-partial.json
|
||||
docker compose run --rm --no-deps app fpol_admin --database /data/fpol.sqlite create-user YOUR_USERNAME
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Caddy owns public ports 80/443 and obtains HTTPS certificates. The app's 8080 port is internal only. Both app and worker use UID 10001 and the persistent `fpol_data` volume. Caddy certificates/config have their own volumes. The entrypoint uses umask 077. Health checks call `/api/health`; the worker starts after the app is healthy. No demo mode is enabled. Source activation is explicit; an idle ingestion worker invents no data.
|
||||
|
||||
Log in, create a league, and share its private invitation link. To reset a password:
|
||||
|
||||
```sh
|
||||
docker compose exec app fpol_admin --database /data/fpol.sqlite reset-link USERNAME
|
||||
```
|
||||
|
||||
Privately give that user `https://YOUR_HOST/#reset/TOKEN`. The link expires in 30 minutes and works once. Do not paste passwords, invitations, session tokens or reset links into public logs/issues.
|
||||
|
||||
## Source setup
|
||||
|
||||
Use [the ingestion guide](ingestion.md). Copy reviewed configuration files into the container or mount an operator-controlled directory. Configure, probe, inspect source status and archived payload/mappings, then activate. Production startup never auto-activates sample mappings. Both coverage and the candidate inventory must be complete before real draft start.
|
||||
|
||||
## Online backup
|
||||
|
||||
Use SQLite's online backup API through Noto while the service is running. Choose a new filename each time; the command refuses to overwrite one.
|
||||
|
||||
```sh
|
||||
docker compose exec app fpol_admin --database /data/fpol.sqlite \
|
||||
backup /data/backups/fpol-2026-10-04.sqlite
|
||||
docker compose cp app:/data/backups/fpol-2026-10-04.sqlite ./fpol-2026-10-04.sqlite
|
||||
chmod 600 ./fpol-2026-10-04.sqlite
|
||||
```
|
||||
|
||||
Store a protected off-host copy. Include the deployed source revisions and source configuration files. The database backup contains accounts, sessions, invites, frozen league data, picks, raw source payloads and observation history. Do not copy only the live SQLite main file while WAL writes are active.
|
||||
|
||||
## Restore
|
||||
|
||||
Stop **both** writers. Keep the original database and sidecars as a rollback set. Restore to a stopped app container; adapt the filename to your chosen backup. Do not restore a backup over a running database.
|
||||
|
||||
```sh
|
||||
docker compose stop app ingest
|
||||
# The existing container can receive files while stopped.
|
||||
docker compose cp ./fpol-2026-10-04.sqlite app:/data/restore.sqlite
|
||||
docker compose run --rm --no-deps --user root app sh -c 'chown 10001:10001 /data/restore.sqlite && chmod 600 /data/restore.sqlite'
|
||||
# Use the image's unprivileged account, backed by the same volume.
|
||||
docker compose run --rm --no-deps app sh -c '
|
||||
set -eu
|
||||
test -f /data/restore.sqlite
|
||||
mkdir /data/before-restore
|
||||
for name in fpol.sqlite fpol.sqlite-wal fpol.sqlite-shm; do
|
||||
if test -f "/data/$name"; then mv "/data/$name" /data/before-restore/; fi
|
||||
done
|
||||
cp /data/restore.sqlite /data/fpol.sqlite
|
||||
chmod 600 /data/fpol.sqlite
|
||||
fpol_admin --database /data/fpol.sqlite rules >/dev/null
|
||||
'
|
||||
docker compose up -d app ingest
|
||||
```
|
||||
|
||||
The ownership step affects only the staged backup, so UID 10001 can read it. Verify SQLite integrity on the offline backup (`PRAGMA integrity_check`), source health, memberships, and the last draft pick. Restored active drafts pause automatically; commissioners resume with a fresh 120-second turn. Restoring an older backup also restores old session/reset state; consider revoking sessions and reset tokens via trusted local SQLite administration after recovery.
|
||||
|
||||
Migrations are forward-only. Back up before upgrades; reverting application binaries after a schema change requires restoring a compatible database backup too. Never use `docker compose down -v` to restart this app: it deletes persistent volumes.
|
||||
@@ -0,0 +1,88 @@
|
||||
# Election ingestion
|
||||
|
||||
`fpol_ingest` is a separate C++ process using Ligo's raw HTTPS client and Noto/SQLite. It supports conditional ETag/Last-Modified requests, a 25-second network deadline, a 16 MiB response limit, exponential failure backoff up to one hour, immutable changed-payload archives, immutable observations, quarantine, and current projections. Enabled count/outcome feeds are polled approximately every 60 seconds; candidate watches daily. Responses request identity encoding. No browser scrapes providers directly.
|
||||
|
||||
## Honest readiness
|
||||
|
||||
As of the implementation session, **no live provider is verified**. The environment cannot open sockets or resolve outbound DNS. Open America's published schema informed a tested adapter; synthetic replay tests are not transport validation. civicAPI has only a capture-only probe: its race/candidate contract still needs a real successful response before a normalizer can be written. The `official-json` adapter is a normalized integration contract, not a claim that arbitrary state websites already emit it. Additional state-specific CSV/XML/JSON adapters and reviewed PDF imports are still required for national coverage.
|
||||
|
||||
Open America documents counts from 22 states, no pre-election candidate catalog, and no race calls. Its `final`, leader, precinct percentage, and candidate `w` fields never award a winner bonus. Documentation: [Open America election API](https://openamerica.io/elections/api/). Attribution in the UI should retain the feed URL and timestamps; the source is official state election offices via Open America.
|
||||
|
||||
## Configure, capture, review, activate
|
||||
|
||||
```sh
|
||||
fpol_admin --database var/fpol.sqlite import data/real/us-2026-10-04-partial.json
|
||||
fpol_ingest --database var/fpol.sqlite configure data/sources/openamerica-nc-house.json
|
||||
fpol_ingest --database var/fpol.sqlite probe openamerica-nc-house
|
||||
fpol_ingest --database var/fpol.sqlite status
|
||||
# Inspect the archived raw response and exact candidate/round mappings first.
|
||||
fpol_ingest --database var/fpol.sqlite activate openamerica-nc-house
|
||||
fpol_ingest --database var/fpol.sqlite run
|
||||
```
|
||||
|
||||
Configuration starts disabled and unverified. The sample NC mappings use official ballot spellings as **proposals**; they have not been matched to an actual provider capture. Update exact aliases after review. A configuration change disables the source and clears its per-race verification checks. Activation requires a validated live observation for **every configured race/role**, not merely an HTTP 200 or one race in the response. Before election night, an empty results payload cannot satisfy this requirement; real draft readiness may need a provider that offers verifiable race coverage before counts arrive.
|
||||
|
||||
`probe` fetches even a disabled source. `once` polls only enabled sources whose next check is due. `disable ID` stops scheduled polling. `activate ID` selects this provider for each configured role/race, replacing that assignment; do this deliberately, with reviewed data. Existing selected counts are never added to another provider's counts.
|
||||
|
||||
Raw changed responses are stored in `source_payloads` keyed by source plus content hash. Use the local SQLite client or a backup to inspect/export them; they are not served through player APIs. `source_checks` records only successful live validations. `observations` retains normalized records, `current_observations` selects the current record, `coverage` assigns one count source and one outcome source per contest, and `source_quarantine` records rejected responses and their archive ID.
|
||||
|
||||
## Adapter configuration
|
||||
|
||||
A configuration has `id`, `kind`, HTTPS `url`, `catalog_id`, and `races`. Each assignment has an internal `race_id` and `role` (`counts` or `outcome`). Standard HTTPS hostnames on port 443 are supported; redirects are reported as HTTP errors for operator review.
|
||||
|
||||
For `openamerica`, also supply `office` (`House`, `Senate`, `Governor`), `counts_until` in UTC, and each assignment's `provider_id` plus a `candidates` object mapping exact `name|party-code` to stable candidacy IDs. Explicit `null` mappings can exclude an aggregate write-in row; unknown rows quarantine the response. Separate fusion ballot lines can map to the same candidacy and their votes are summed once. Duplicate provider rows, wrong-race IDs, negative counts and impossible totals are rejected. Do not map different people together or assign aggregate write-ins a roster slot.
|
||||
|
||||
Open America does not expose a round identifier. The configured cutoff prevents a later election from silently overwriting November counts. Review each state's feed semantics, including ranked-choice reporting; do not activate an adapter if it cannot supply first-choice counts. After the cutoff, reviewed first-round corrections need an official-source adapter with explicit round metadata. Sample NC cutoffs are conservative operational bounds, not a national runoff calendar.
|
||||
|
||||
The `official-json` endpoint returns:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema_version": 1,
|
||||
"observations": [
|
||||
{
|
||||
"race_id": "2026-nc-senate-general",
|
||||
"kind": "counts",
|
||||
"round": "november_first",
|
||||
"source_time": "2026-11-04T03:00:00Z",
|
||||
"total_votes": 1000,
|
||||
"votes": [
|
||||
{ "candidate_id": "2026-nc-senate-general-roy-cooper", "votes": 480 }
|
||||
]
|
||||
},
|
||||
{
|
||||
"race_id": "2026-nc-senate-general",
|
||||
"kind": "outcome",
|
||||
"round": "general",
|
||||
"source_time": "2026-11-04T04:00:00Z",
|
||||
"status": "reporting",
|
||||
"winner_id": null
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**The numbers above are schema examples, not election results.** `source_time` may be null when unknown; use UTC `Z` or `+00:00` otherwise. Source timestamps and receipt/check times remain separate. Counts may contain zero values, but zero total or a missing candidate produces an unknown score. Candidate totals cannot exceed the reported race total; the total may include explicitly excluded write-ins. Only `november_first` counts are accepted. A later runoff/RCV outcome may use its own round identifier without altering those counts.
|
||||
|
||||
Outcome status is `reporting`, `pending_round`, `called`, or `certified`. Only called/certified outcomes have a `winner_id`. A newer reporting/pending record retracts a provisional call. A certified outcome takes precedence over subsequent provisional records; a newer certified correction may change the winner. Older source timestamps are archived without moving the current projection backward. Missing races do not erase previous data. Failed or ambiguous responses preserve the last good observation and mark source health stale.
|
||||
|
||||
## Candidates and reviews
|
||||
|
||||
```sh
|
||||
fpol_ingest configure data/sources/nc-candidate-watch.json
|
||||
fpol_ingest watch nc-candidate-watch
|
||||
fpol_ingest configure data/sources/civicapi-status.json
|
||||
fpol_ingest probe civicapi-status
|
||||
```
|
||||
|
||||
`candidate-watch` captures changed public source files daily for human review; it does not blindly parse PDF names or silently change a frozen draft pool. Import a new validated catalog ID after reviewing changes. Preserve stable candidacy IDs across spelling/party-line updates; merge fusion lines; exclude aggregate write-ins. Individually qualified write-in candidates need their own reviewed identity and eligibility evidence. Old catalog documents and draft snapshots remain immutable.
|
||||
|
||||
[The inventory](../data/contests_2026.json) covers the 50 states' scheduled November House/Senate/governor contests, including safe and uncontested seats, with FL/OH special Senate contests distinct. Round data stays separate from contest identity. House at-large seats use internal district `01`; map providers' `00` explicitly. The inventory is a scope checklist, not evidence that candidate or result coverage is complete.
|
||||
|
||||
## Replay without overstating verification
|
||||
|
||||
```sh
|
||||
fpol_ingest replay SOURCE_ID captured-or-fixture.json
|
||||
```
|
||||
|
||||
Replay archives and validates the file but never grants live verification. It can publish observations only into an explicitly fictional `mode: demo` catalog; real catalogs require network observations. Demo replays can assign empty demo coverage slots so practice standings can be exercised. Replaying an old file never unlocks real drafting. The first milestone's immutable `results` snapshots and `score-preview` remain a separate v1 lab contract; the league scorer uses `v2-november-share`.
|
||||
+31
-22
@@ -1,39 +1,48 @@
|
||||
# Local verification — 2026-10-04
|
||||
# Verification — league milestone, 2026-10-04
|
||||
|
||||
## Passed
|
||||
## Passed locally
|
||||
|
||||
- Both `fpol_server` and `fpol_admin` compile in Debug and Release using the available **GCC 16.2.1** host compiler and C++23.
|
||||
- 25 core tests pass against the production admin executable in both configurations. These cover Noto migrations, reopening SQLite, import idempotency, immutable IDs, corrections, chronological replay, mode isolation, roster eligibility, rounding, capacity, missing data, ambiguous leader previews and round mismatches.
|
||||
- The real Michigan snapshot imports successfully; candidate counts match the coverage report. Demo and real data are seeded in the ignored local `var/fpol.sqlite`.
|
||||
- Strict TypeScript checking and the Vite production build pass.
|
||||
- Shared Modulus formatting and `git diff --check` pass. The bootstrap is unchanged from the canonical shared file.
|
||||
- Server help and invalid-startup tests pass without sockets.
|
||||
- C++23 Debug and Release builds of `fpol_server`, `fpol_admin`, and `fpol_ingest` with the available **GCC 16.2.1** host compiler.
|
||||
- 25 original domain/persistence tests: immutable imports, reopening SQLite, migrations, capacity, eligibility, score rounding, mode isolation, missing data, replay corrections and original round behavior.
|
||||
- 19 application/ingestion tests against the production C++ executables and real SQLite databases: authentication/CSRF/rate limits, invite registration/capacity/expiry/revocation, private league permissions, password change/recovery/session revocation, partial real catalog paging, private queues, snake order, timeouts, pause/restart, simultaneous idempotent picks, cross-league ownership, complete 12-team/144-pick drafts, global party-slot capacity, first-round/runoff separation, retractions/corrections/older observations, quarantine, fusion-line aggregation, unverified-feed refusal, per-race activation gates, sourced ratings permissions/immutability/freeze, online backups, and candidate-watch content change detection.
|
||||
- Strict TypeScript checking and Vite production build, including the separate lab entry point.
|
||||
- Shared Modulus C++/Python formatting, `git diff --check`, and canonical-bootstrap comparison.
|
||||
- Updated Ligo library and its test executable compile. The new socket-independent response/header metadata test passes.
|
||||
- Compose configuration parses successfully with `FPOL_DOMAIN=game.example docker compose config --quiet`.
|
||||
- The combined real candidate import succeeds: 115 candidates, 30 contests, explicitly partial. The national inventory has 506 contests.
|
||||
|
||||
## Environment limits
|
||||
The full Debug CTest run passed 25 domain plus the then-current 18 application tests. After the final candidate-watch regression was added, all 19 application tests passed separately in Debug. Release passed the 25 domain and 18 application tests, then the added watch regression separately after rebuilding. These are local fallback checks, not a successful run of the configured GCC 12 pipeline.
|
||||
|
||||
The full Debug CTest run executes all 25 core tests successfully, then runs eight server tests. Two server tests pass; six cannot execute their socket-dependent paths because the sandbox rejects socket creation with `Operation not permitted`. The suite is deliberately still failing here, not skipped or reported green. HTTP success/error envelopes, real request transport, static delivery and shutdown need the normal development/CI environment. A browser interaction/visual check also remains outstanding.
|
||||
## Blocked checks — not passed or skipped
|
||||
|
||||
Docker's socket is inaccessible in this environment, and GCC 12 is not installed on the host. Consequently, the configured Modulus GCC 12/container workflow could not be verified here. The fallback builds local Modulus/Noto sources into ignored directories under this repository and uses already-cached Boost/OpenSSL/SQLite plus the existing local Ligo build. Release application compilation maps cached dependency configurations to Debug; this is an optimized application check, not a fully optimized dependency build or performance measurement. No shared library sources or dependency caches were modified.
|
||||
The full Debug CTest suite remains **red**: two server tests (help and invalid startup) pass, while seven HTTP/socket checks cannot execute because socket creation is rejected with `Operation not permitted`. These include the new cookie/Secure/HttpOnly/origin/CSRF/query checks. Ligo's new raw HTTP wire test also stops when its server cannot bind.
|
||||
|
||||
The committed Gitea workflow still runs the intended GCC 12 debug/release builds and the full HTTP suite. Run it, or the README's normal Modulus checks, before merging.
|
||||
The real-browser smoke test was attempted and stops at Node's `listen EPERM` before Chromium can exercise the app. Therefore no interactive/visual browser pass or screenshots are claimed. The checked-in Node/CDP test uses two isolated browser sessions and the actual C++ server; CI now invokes it after frontend/backend builds.
|
||||
|
||||
## Reproduce these local fallback checks
|
||||
A real Open America probe was attempted. It failed DNS resolution (`Host not found … try again later`) and left the source **disabled, unverified, with no successful capture**. No live election results or national feed coverage are claimed. civicAPI remains a capture-only probe pending an actual response contract. Provider fixtures used by tests are synthetic and never count as verification.
|
||||
|
||||
These paths are local artifacts, not portable prerequisites:
|
||||
Docker's daemon/socket is inaccessible and GCC 12 is not installed on this host. The Docker image, Caddy startup/certificate issuance, source-based Conan helper on a fresh networked machine, and the full GCC 12 debug/release/HTTP/browser pipeline still need execution outside this environment. Compose parsing is not a container deployment test.
|
||||
|
||||
## Build context and dependency handoff
|
||||
|
||||
Fallback builds use ignored `build/kickoff_debug`, `build/kickoff_release`, and `build/verification_*` directories, with locally built shared libraries and cached Boost/OpenSSL/SQLite. Release application compilation maps cached dependency configurations to Debug; it is an optimized application check, not a fully optimized dependency build or benchmark.
|
||||
|
||||
**The sibling Ligo repository has required source changes** in its service/HTTP interfaces and implementation, plus tests. They add optional query parsing, request headers, custom response status/headers, and raw HTTP client exchange. Default query handling and existing aggregate initialization remain compatible. Carry those library changes with this application change. The package-based CI needs that matching Ligo revision published/available before it can pass; `tools/build_workspace.py` and the Docker source build use the local sibling revision without publishing.
|
||||
|
||||
No deployment, library publishing, Git commit, or push was performed. Existing local accounts/passwords were not created or replaced. Test users live only in temporary databases; the failed provider probe is in ignored `build/source-probe.sqlite`.
|
||||
|
||||
## Reproduce
|
||||
|
||||
On a normal networked host, use the [README](../README.md) and [deployment guide](deployment.md). In this existing offline workspace, the configured fallback paths are:
|
||||
|
||||
```sh
|
||||
cmake --build build/kickoff_debug
|
||||
cmake --build build/kickoff_release
|
||||
python3 tests/test_core.py build/kickoff_debug/fpol_admin
|
||||
python3 tests/test_core.py build/kickoff_release/fpol_admin
|
||||
python3 tests/test_application.py build/kickoff_debug/fpol_admin build/kickoff_debug/fpol_ingest
|
||||
ctest --test-dir build/kickoff_debug --output-on-failure
|
||||
npm --prefix frontend run build
|
||||
node tests/browser.mjs build/kickoff_debug/fpol_server
|
||||
```
|
||||
|
||||
The local database and frontend assets are already prepared. Outside the socket-restricted sandbox, the locally built prototype can be started from this repo root:
|
||||
|
||||
```sh
|
||||
build/kickoff_debug/fpol_server --web-root frontend/dist
|
||||
```
|
||||
|
||||
Open `http://127.0.0.1:8080`. Provider JSON transport and automatic election-night coverage are separate outstanding checks listed in [the data report](data-coverage.md).
|
||||
Do not interpret the socket-independent successes as substitutes for the blocked HTTP/browser tests or real source verification.
|
||||
|
||||
Reference in New Issue
Block a user