{"id":50500864,"url":"https://github.com/prof-faustus/cardtable","last_synced_at":"2026-06-02T11:04:01.642Z","repository":{"id":361367772,"uuid":"1254020424","full_name":"prof-faustus/cardtable","owner":"prof-faustus","description":"Dealerless distributed card-game protocol on BSV. Transaction-native state machine; first game In-Between. Research code, regtest only.","archived":false,"fork":false,"pushed_at":"2026-05-30T11:06:02.000Z","size":199,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-30T11:13:07.521Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/prof-faustus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-30T03:47:11.000Z","updated_at":"2026-05-30T11:06:19.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/prof-faustus/cardtable","commit_stats":null,"previous_names":["prof-faustus/cardtable"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/prof-faustus/cardtable","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prof-faustus%2Fcardtable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prof-faustus%2Fcardtable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prof-faustus%2Fcardtable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prof-faustus%2Fcardtable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/prof-faustus","download_url":"https://codeload.github.com/prof-faustus/cardtable/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prof-faustus%2Fcardtable/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33818598,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-02T02:00:07.132Z","response_time":109,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-02T11:03:59.257Z","updated_at":"2026-06-02T11:04:01.627Z","avatar_url":"https://github.com/prof-faustus.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# cardtable — Dealerless Distributed Card-Game Protocol on BSV\n\n[![CI](https://github.com/prof-faustus/cardtable/actions/workflows/ci.yml/badge.svg)](https://github.com/prof-faustus/cardtable/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n\n\n\u003e **Research code, in early scaffolding.** This repository implements the\n\u003e protocol specified in [`PROJECT_SPEC.md`](PROJECT_SPEC.md) and the spec\n\u003e documents under [`spec/`](spec/). Per the project's token model, tokens\n\u003e carry **no external monetary value** and the system is not a regulated\n\u003e gambling product. See [LICENSE](LICENSE).\n\n## What this is\n\n`cardtable` is a transaction-native, peer-to-peer, non-custodial protocol for\nmultiplayer card games on Bitcoin SV (post-Genesis). Every game event is a\nsigned BSV transaction; every game state is a committed UTXO with one\ncooperative successor branch and one timeout-default successor branch; every\nfailure mode resolves to a deterministic on-chain consequence rather than an\noperational judgement call.\n\nFirst production target: **In-Between** (Acey-Deucey).\n\n## Source of truth\n\n| File | Role |\n|---|---|\n| [`PROJECT_SPEC.md`](PROJECT_SPEC.md) | Working build spec; coding standards; project structure; build order; do-not lists |\n| [`spec/`](spec/) | Per-aspect protocol specification (state machine, transaction types, script templates, timeout rules, recovery rules, serialisation, ordering, card protocol, wire protocol, peer discovery) |\n| [`spec/test-vectors/`](spec/test-vectors/) | Canonical input/output vectors that bind every implementation to identical behaviour |\n| [`docs/adr/`](docs/adr/) | Architecture Decision Records covering every design choice made under ambiguity |\n\n## Stack (per PROJECT_SPEC.md §Technology Stack)\n\n- **Client:** TypeScript (strict), React 18, Vite, Zustand, Dexie, Web Crypto, BSV TypeScript SDK\n- **Backend:** Go 1.22+, WebSocket relay, Aerospike, Kafka, BSV Go SDK\n- **Out of scope:** off-chain payment networks, second-layer rollups, alternative script extensions, Postgres/Redis for game state, ORM, GraphQL, server-managed game state. Every state transition is on-chain.\n\n## Build phases (per PROJECT_SPEC.md §Build Order)\n\n1. **Spec + protocol-types** — write `spec/`, the `protocol-types` package\n2. **State engine + script templates** — deterministic rules + BSV script construction\n3. **Open-information prototype** — table flow without concealed cards\n4. **Concealed single-card** — entropy commit/reveal, encrypted card UTXOs\n5. **Multi-card In-Between** — full game, pre-signed fallback graph, transcript replay\n6. **Adversarial hardening** — all 14 named scenarios + deterministic replay\n\nThis repository is at **Phase 0** (skeleton only) at the time of this\ncommit. Subsequent commits will fill each phase in turn.\n\n## Repository layout (per PROJECT_SPEC.md §Project Structure)\n\n```\ncardtable/\n├── PROJECT_SPEC.md, README.md, LICENSE\n├── spec/                # Protocol specification (source of truth for protocol behaviour)\n├── packages/            # Shared TypeScript packages\n│   ├── protocol-types/\n│   ├── state-engine/\n│   ├── script-templates/\n│   └── crypto-cards/\n├── apps/                # Runnable services\n│   ├── client-web/      # React + Vite browser client\n│   ├── relay-go/        # Go WebSocket relay\n│   ├── indexer-go/      # Go indexer service\n│   └── spv-service-go/  # Go SPV proof / header service\n├── tests/               # Cross-package and adversarial tests\n├── tools/               # Simulators, transcript verifier\n└── docs/                # Architecture notes, ADRs, runbooks\n```\n\nEmpty subdirectories are kept tracked with a `.gitkeep` file until the\ncorresponding phase fills them.\n\n## Critical rules (excerpted from PROJECT_SPEC.md, repeated here for visibility)\n\n- **Build to BSV consensus and the post-Genesis opcode set.** Use the BSV TypeScript / Go SDKs only.\n- **Script is Turing-complete on BSV post-Genesis.** Timelocks live at the transaction level (`nLockTime`, input `nSequence`); no in-script timelock opcode is used by any cardtable template.\n- **Tokens carry no external value.** This is not a regulated gambling product.\n- **Zero fabrication.** Every number, claim, and technical statement traces\n  to a source or is marked as an assumption with a tracked obligation.\n- **No silent assumptions.** Hidden assumptions are defects; declare them on\n  the face of the document.\n\n## Quickstart\n\n```bash\n# 1. Install\npnpm install\n\n# 2. Run every TS + Go suite locally (offline)\npnpm ci                                       # workspace build + test\n(cd apps/relay-go \u0026\u0026 go test -v ./...)        # Go suite\n\n# 3. Run the relay locally\n(cd apps/relay-go \u0026\u0026 go build -o ../../bin/relay ./cmd/relay)\n./bin/relay --addr :8080 --ws-addr :8081 \\\n  --game 00000000000000000000000000000000000000000000000000000000000000aa \\\n  --start-height 100\n\n# 4. Drive a full mental-poker round against the running relay\nCARDTABLE_RUN_LIVE=1 \\\nCARDTABLE_RUN_FULL_ROUND=1 \\\nCARDTABLE_WS_URL=ws://localhost:8081/ws \\\nCARDTABLE_GAME_ID=00000000000000000000000000000000000000000000000000000000000000aa \\\n  pnpm --filter @cardtable/integration-tests test\n\n# 5. Or use Docker\ndocker compose up --build relay               # local build\ndocker run -p 8080:8080 -p 8081:8081 \\\n  ghcr.io/prof-faustus/cardtable-relay:latest # published multi-arch image\n```\n\nBrowser client:\n\n```bash\n(cd apps/client-web \u0026\u0026 pnpm vite build \u0026\u0026 pnpm vite preview --port 4173)\n# then open http://localhost:4173 and click \"Connect to relay\"\n```\n\nRecord a transcript and verify it offline:\n\n```bash\nnode ./tools/transcript-recorder/dist/index.js \\\n  --ws ws://localhost:8081/ws \\\n  --game-id 00000000000000000000000000000000000000000000000000000000000000aa \\\n  --out ./session.jsonl\n\nnode ./tools/transcript-verifier/dist/index.js \\\n  --transcript ./session.jsonl \\\n  --game-id 00000000000000000000000000000000000000000000000000000000000000aa\n\n# OR the Go-side audit harness:\n(cd apps/relay-go \u0026\u0026 go build -o ../../bin/indexer ./cmd/indexer)\n./bin/indexer --transcript ./session.jsonl \\\n  --game-id 00000000000000000000000000000000000000000000000000000000000000aa\n```\n\n## Building on Windows\n\nThe Quickstart works as-is on Linux/macOS and in CI. On Windows hosts a few\nenvironment quirks bite; apply these and every suite passes:\n\n- **`pnpm install` fails with `UNABLE_TO_VERIFY_LEAF_SIGNATURE`** — caused by\n  corporate TLS inspection re-signing the npm registry. Trust the Windows root\n  store via Node's system-CA flag (Node ≥ 22):\n\n  ```powershell\n  $env:NODE_OPTIONS = \"--use-system-ca\"\n  pnpm install\n  ```\n\n  Keep `NODE_OPTIONS=--use-system-ca` set for `pnpm install`/`build`/`test`.\n\n- **`go test ./...` reports `... contains a virus or potentially unwanted\n  software` and FAILs** — a false positive from the host antivirus (e.g.\n  Norton/Defender) quarantining freshly-linked Go `*.test.exe` binaries (the\n  `pkg/wire` test binary is the usual trigger). The code is fine. Build the\n  test binaries with `-trimpath`, which changes the linked output enough to\n  clear the heuristic, and make it the default:\n\n  ```powershell\n  go env -w GOFLAGS=-trimpath\n  go test ./...                 # now green in one command\n  ```\n\n  A *cold* full relink (`go clean -testcache` then `go test ./...`) can still\n  intermittently flake one timing-sensitive test\n  (`internal/spv/TestHTTPHeightSource_TracksLatest`, a 2-second HTTP-poll\n  deadline) when the AV scans every new binary at once. Warm re-runs are\n  stable. To eliminate it permanently, add a folder exclusion in your AV for\n  Go's temp dir (set a stable one with `go env -w GOTMPDIR=C:\\Users\\\u003cyou\u003e\\go-tmp`\n  and exclude that folder).\n\n- **Port `8081` already in use** — on machines running WSL, `wslrelay.exe`\n  binds `127.0.0.1:8081`. Run the relay on an alternate port and point the\n  integration tests at it:\n\n  ```powershell\n  .\\bin\\relay.exe --addr :8092 --ws-addr :8091 `\n    --game 00000000000000000000000000000000000000000000000000000000000000aa --start-height 100\n  $env:CARDTABLE_WS_URL = \"ws://127.0.0.1:8091/ws\"\n  ```\n\n  The `live-full-round` integration test and the online browser-smoke test each\n  require a **fresh** relay (the relay holds session state in memory, so a\n  reused seat collides). Restart the relay between those runs.\n\n## How to contribute\n\nRead `PROJECT_SPEC.md` and the per-aspect spec docs under `spec/`\nend-to-end. Then check `STATUS.md` for the current phase + the\nsubstantive gaps remaining. Tests live next to their code:\n`packages/*/__tests__/`, `apps/relay-go/**/_test.go`, plus the\ncross-system suites under `tests/integration/` and\n`tests/browser-smoke/`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprof-faustus%2Fcardtable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprof-faustus%2Fcardtable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprof-faustus%2Fcardtable/lists"}