Rabble

Rabble is a small Lace-backed multiplayer word game. Games, players, guesses, registration requests, grants, and revocations are immutable records. The Node CLI and browser share one JavaScript action/projection core, and records move only through explicit bounded sync.

The base frontend entry is //u//rabble//index.html; the packaged HTTP compatibility host serves //u//rabble/http//index.html.

Authority and conflicts

A game steward marks a rabble/game descriptor. Players mark their own rabble/player and exact-linked rabble/guess records. A waypoint steward marks registration grants and revocations. Registration controls endpoint admission only; it does not grant game or player authority.

For each (Waypoint-Steward, Subject), greatest TAI is current and greatest hash wins at equal TAI. The result is active or revoked. Without a statement, a request gives requested; otherwise status is missing. There is no registration conflict state.

A Game value is a portable domain key, not record identity. Exactly one valid descriptor hash defines it. Multiple descriptors are an explicit conflict and no TAI winner is chosen; the game, players, and guesses are excluded from the game view.

Current player state uses greatest TAI then greatest hash. Each guess remains authorized by its exact historical active Player+Link; a later leave or rejoin does not rewrite that link, and an inactive linked record never authorizes a guess. The endpoint independently enforces author equality for game, player, and guess records even after registration.

Guesses sort by TAI then hash. Their hashes choose temporary targets from the current option set and feedback filters that set. TAI is presentation data, not trusted chronology. This is a public low-stakes game, not an anti-cheat design: game words, names, guesses, notes, and registration metadata may be exposed as whole records. Revocation changes future selection, not bytes already copied.

CLI usage

Create an identity and game:

npm --prefix incubator/rabble run rabble -- \
  --identity incubator/rabble/.lace-data/alice-identity.json identity create
npm --prefix incubator/rabble run rabble -- \
  --store incubator/rabble/.lace-data/alice \
  --identity incubator/rabble/.lace-data/alice-identity.json \
  game create --title "Friday Rabble" --words crane,slate,bring,jolly

Mutations remain local until explicit exchange:

npm --prefix incubator/rabble run rabble -- \
  --store incubator/rabble/.lace-data/alice \
  --identity incubator/rabble/.lace-data/alice-identity.json \
  sync once ws:127.0.0.1:8867/interlace \
  --waypoint-steward V.8qgOfsaEJkK1tzX51sTT9NKdM8J2SrzQq6k8cRPzvP0.H3

Inspect local registration state:

npm --prefix incubator/rabble run rabble -- \
  --store incubator/rabble/.lace-data/alice \
  --identity incubator/rabble/.lace-data/alice-identity.json \
  registration status \
  --waypoint-steward V.8qgOfsaEJkK1tzX51sTT9NKdM8J2SrzQq6k8cRPzvP0.H3

--game GAME narrows game, player, and guess exchange but never bypasses active registration. Run with --help for create, join, guess, registration review, and sync commands.

Packaged browser host

Build and run the complete Rabble host with Deno:

npm --prefix incubator/rabble run host

The command builds dist/, then serves the browser interface and its Interlace endpoint together on http://127.0.0.1:8867/. Host records persist under .lace-data/rabble/host. Pass host options after --, for example --listen ws:127.0.0.1:0/interlace or --store-path PATH.

The browser provides the same local game, join, guess, registration, and sync actions. It does not add implicit startup or post-write synchronization.

Validation

npm --prefix incubator/rabble test
git diff --check

The package tests cover the integrated build shape, projection/action behavior, filesystem reopen, CLI subprocesses, paired WebSocket exchange, and endpoint admission policy.