# Chess on CBCL

A playable browser demonstration of two independently validating chess replicas, with Stockfish as an optional local opponent. CBCL verifies the message contract and role/cause checks; chess.js independently verifies each claimed board transition. Real Ed25519 signatures bind the complete message to the game, dialect and pinned public player keys. Neither a model nor Stockfish decides which proposals the clients accept.

```sh
cd outputs/cbcl-chess-2026-11-02
npm ci --ignore-scripts
npm test
npm start
```

Open http://127.0.0.1:18179/. You play White against Stockfish by default; Easy, Medium and Strong adjust skill and thinking time without claiming a calibrated Elo. Choose Two players for hotseat play. Click a piece and destination, then Sign and send, or enter UCI such as e2e4. Promotion defaults to queen and can be changed before selecting a destination. The illegal-knight button signs b1b3: CBCL accepts its protocol structure, while both chess clients reject its board effect and retain the attempt. Export a signed record and replay it in a different browser without player private keys.

Validation: 20 Node tests pass, covering the chess/protocol and UCI worker lifecycle. browser-check.mjs exercises hotseat clicks, signature-backed illegal/legal transitions, export/import, fork freeze, a 390px layout and page-error monitoring. engine-browser-check.mjs uses the actual Stockfish WASM for three human/engine turns, restart cancellation, hotseat switching, replay and mobile layout. Run these with the static server active and Playwright installed; they default to the sibling ar-crawl service's Playwright installation, or set CHESS_PLAYWRIGHT to another Playwright module path. Browser results and desktop/mobile screenshots are retained here. ar-crawl loaded the original page, but its service timed out waiting for click stability; successful interactive acceptance used separate direct Playwright browsers.

Stockfish.js 19.0.1 lite single-threaded runs in a Web Worker with no remote API, model bill or cross-origin isolation requirement. A fresh worker per search is terminated after bestmove or cancellation. The full predecessor move history is sent through UCI; output supplies a proposal only. The host signs Black's CBCL message and both replicas independently validate it. Switching opponent, importing a record or starting a new game cancels stale work; errors leave manual hotseat play available. Exported records include engine moves, never engine or player private keys.

Unmodified engine assets were selectively extracted from the integrity-verified stockfish@19.0.1 npm tarball. Only the lite worker and matching WASM are needed (about 1.9 MB together); the complete npm bundle was not installed. vendor/stockfish/provenance.json records the tarball integrity and individual asset hashes. GPLv3 is retained in vendor/stockfish/Copying.txt; the interface and vendored README link to corresponding source and build instructions at https://github.com/nmrugg/stockfish.js/tree/v19.0.1. This engine has its own license; do not describe it as Apache-2.0 CBCL code.

`npm run demo` runs the same protocol in Node and writes demo-transcript.json. It demonstrates an illegal move followed by legal moves and matching independent board states. Each run generates fresh identities.

The browser is a local demonstration with an engine or hotseat opponent. Both player private keys are created and held only in browser memory; reload loses them. The two replicas have separate message stores but execute in the same process and are not a network or Byzantine-deployment test. The HTTP server serves static assets only and never sequences or judges moves. Remote identity exchange, encrypted delivery, durable keys, clocks, matchmaking, agent connectors and production packaging are not implemented. A transcript import trusts its supplied initial public configuration; the participant identities and rules fingerprint require an independent check. Imported games are read-only.

The frozen, content-addressed dialect declares white-move and black-move once, then uses `(protocol (then begin (repeat 512 white-move black-move)))` for 1,024 plies (512 full moves). A signed cast-bearing opener pins the initial board and application policy. The root is the protocol's begin witness, rather than an ordinary preceding gameplay step. Moves cite its hash and then the previous move's hash. The native repeated-position resolver determines each move’s position from its causal ancestry; wire messages retain their base verbs. The move limit ends the demo without declaring a chess winner.

All authenticated messages remain evidence. Missing predecessors stay pending; invalid chess transitions have no board effect and cannot authorize a descendant. Each client reconstructs a position from its complete predecessor move history, preserving repetition information. Duplicates do not add moves. A legal turn is distinct from cryptographic authenticity and from native CBCL admission.

If a player signs two legal successors of one position, clients expose the conflicting signed evidence and freeze at the common predecessor. Opposite arrival orders converge after both records are delivered. Until delivery, each view is provisional: this provides neither finality nor prevention of player equivocation. No server ordering, hash winner or silent branch selection is used. There is deliberately no unilateral fork-resolution button.

chess.js 1.4.0 supplies movement legality, castling, en passant, promotion, check and mate. The demo automatically ends on the library's draw conditions, including threefold repetition and the fifty-move rule. That differs from tournament rules requiring players to claim certain draws. It has no clocks or resignation/draw-offer protocol. Custom test starting positions must have White to move.

The CBCL WASM was rebuilt from clean state-rules-spec revision 6d18ef8e04a273aa918b572217f96c8c36bc200a with matching wasm-bindgen 0.2.114. Its SHA-256 is cf709290ebe6de769e1c64c974b7e388ef62b95231047f4b4d30214395468019; vendor/cbcl/cbcl_wasm.provenance.json records the build. Existing JavaScript wrappers are retained with regenerated wasm-bindgen glue. This demo does not exercise bounded counters or claim their integration. CBCL is Apache-2.0, with its license retained in vendor/cbcl/LICENSE. chess.js is BSD-2-Clause; its license is included in the pinned npm dependency.

This is a concrete demonstration of application invariants above CBCL, not a formal proof of chess correctness, a production security review or a claim about CoordX's implementation. Its market message is supportable: each client checks an authenticated action against the agreed communication contract and a deterministic application rule checker.

## Independent delivery views

The demo now has separate White, Black and Observer stores. Select a client tab to inspect its board and evidence. A player signs and verifies its own move, then queues identical signed envelopes for the other two clients. Stockfish reads Black's store and cannot reply until White's move reaches it. Each seat must wait for its opponent's signed move before playing again.

Turn off **Deliver automatically** to inspect individual messages. Turn off **Mailbox online** to block mailbox delivery, then use **Send directly** to pass the unchanged envelope to the recipient. These are local delivery simulations, not remote networking or a demonstration of any competitor's behavior. Genesis is initially delivered to all three clients. Export includes all signed messages created in the simulation, even messages not yet delivered to every client; import replays that full public record read-only.

**Start out-of-order example** starts a fresh local game with automatic delivery off. White and Black exchange e2e4/e7e5, while the Observer receives e7e5 first. The observer stays at its initial board with a pending dependency. Deliver White's queued e2e4 message to the Observer: both moves then apply. No mailbox sequencing decision is needed. Boards remain provisional if a signer equivocates.

Validation: `npm test` runs 22 tests, including causal turn restrictions, out-of-order observer catch-up, and unchanged-envelope direct delivery. `node delivery-browser-check.mjs` checks the real browser, real Stockfish waiting for delivery, paused mailbox/direct delivery, pending spectator recovery, and mobile layout. Browser scripts expect the local server on port 18179 and the sibling ar-crawl Playwright installation.

## P2P Chess controls

The product title is **P2P Chess · powered by CBCL**, with a visible local-simulation label. This prototype has no remote peer connection yet. It makes no factual claim about CoordX's implementation or mailbox sequencing.

Drag your own piece to its destination to sign and submit a move immediately. Mouse, pen and touch use pointer events. Illegal drops go through the existing application validation and remain signed evidence. Dropping outside the board cancels. Click-to-move plus the Sign & send button remains available. Select a promotion piece before dragging a pawn to the last rank.

The history slider displays the selected client's accepted causal line, from its initial board to its current head. Historical positions cannot submit moves. **Back to live** restores the current board; delivery and engine work continue while inspecting history. This is board history, not a rewind of message arrival events. Switching clients and starting/importing a game return to live.

Browser validation: `node drag-browser-check.mjs` exercises actual mouse and touch input, illegal moves, observer restrictions, cancellation and click compatibility. `node history-browser-check.mjs` verifies initial/intermediate board replay, signing restrictions, return to live, reset behavior and mobile layout.

Expand **Raw CBCL message** on any record entry or delivery to see the exact message string, message ID, envelope version and Ed25519 signature. Message text is displayed without reformatting and rendered as text. This is demo-wide inspection: undelivered messages are visible to the viewer even when the selected client has not received them. Expansion persists across delivery updates. Imported public transcripts support the same inspection.

Expand **Chess dialect** to inspect the exact verified dialect source and its content hash, compare that hash to the current game's pinned dialect, or download the unchanged source as `chess-dialect.cbcl`. The displayed source uses the active bounded-repeat implementation and two move verbs. Earlier exports using the old numbered-verb dialect have a different pinned dialect and cannot be imported into this version. Browser verification checked exact source/hash, byte-identical download, mobile fit and absence of page errors.

## Copy framing and dialect identity

The demo copy follows the local alignment paper, `../papers/papers/2026-cbcl-alignment/main.md`, and its working drafts on public conformance, partial information, host enforcement and attributable violations. It focuses on an inspectable shared contract, authenticated proposals and verification before board changes. Missing evidence stays pending; receiving both conflicting moves exposes a fork. This demo uses a fixed contract and does not demonstrate runtime contract negotiation, guarantee fair outcomes or implement external-effect enforcement.

**Chess** is the human-readable dialect name. The canonical protocol identity remains the native `dialectHash` result. Verified that the source definition name, game configuration and canonical hash agree, and whitespace changes preserve the hash. The protocol initializer explicitly checks the hash after assigning the self-addressed name. The UI separates the friendly name from the canonical identity.

## Cloudflare Pages

The static deployment is https://cbcl-chess.pages.dev/. Build and redeploy with an authenticated Wrangler CLI:

```sh
npm ci --ignore-scripts
npm test
npm run deploy
```

`npm run build` creates `dist/` from the browser entry points, vendored CBCL and Stockfish assets, and the pinned chess.js module and license. Cloudflare `_headers` preserves the local server’s content security policy and enables WebAssembly compilation. Only `dist/` is published; development tools, test outputs and session files stay outside the deployment. Hosting does not change the demo’s local three-replica simulation into remote multiplayer.
