diff --git a/.gitignore b/.gitignore index 5632860..d111ba5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target +/.lanspread-peer-cli/ /game.db /thumbnails/ diff --git a/CLAUDE.md b/CLAUDE.md index 5387ac3..14d547d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -36,6 +36,11 @@ Never use normal cargo ... commands, use the just ... commands instead. There is only one wire version — the current one. No legacy peers, no compatibility shims, no fallback paths for older builds. Anyone who wants to interop must run the current build; everyone else is out. Do not add backward-compat code, `#[serde(other)]` escape hatches, or "what if an old peer sends X" defenses. +## Manual CLI testing (docker container) + +Start `just peer-cli-alpha`, `just peer-cli-bravo` and `just peer-cli-charlie` each in its own terminal. You then have 3 peers that you can interact with via stdin/stdout (JSONL). +Use this setup to manually test peer functionality. + ## General info See `README.md`. diff --git a/PEER_CLI_SCENARIOS.md b/PEER_CLI_SCENARIOS.md new file mode 100644 index 0000000..6b20222 --- /dev/null +++ b/PEER_CLI_SCENARIOS.md @@ -0,0 +1,26 @@ +# Peer CLI P2P Scenarios + +This matrix tracks the headless peer-to-peer contract exercised through +`lanspread-peer-cli`. It intentionally avoids the GUI and uses direct connect +for deterministic local runs; mDNS/macvlan remains an environment smoke path. + +## Scenario Matrix + +| ID | Scenario | Setup | Expected result | +| --- | --- | --- | --- | +| S1 | Startup scan | Start one peer with `fixture-alpha`. | Peer emits `local-peer-ready` and `local-games-updated`; catalog fixture games are `downloaded=true`, `installed=false`, `availability=Ready`. | +| S2 | Direct connect handshake | Start alpha and bravo, send alpha `connect` to bravo's ready address. | Both peers record one remote peer, no self-peer entry appears, and each peer receives the other's library. | +| S3 | Remote aggregation | Empty client connects to alpha and bravo. | `list-games` shows remote-only games once; shared `ggoo` has `peer_count=2`, unique games have `peer_count=1`. | +| S4 | Single-source download, no install | Empty client connected to bravo downloads `bfbc2` with `install=false`. | Client emits `got-game-files`, `download-begin`, `download-finished`, then local `bfbc2` is `downloaded=true`, `installed=false`; root files exist and `local/` does not. | +| S5 | Auto-install download | Empty client connected to bravo downloads `cnctw` with default install. | Download finishes, install begins and finishes, and local `cnctw` is `downloaded=true`, `installed=true` with `local/fixture-payload.txt`. | +| S6 | Manual install and uninstall | After S4, client sends `install bfbc2`, then `uninstall bfbc2`. | Install marks `bfbc2` installed and creates `local/`; uninstall removes `local/` while preserving downloaded root files. | +| S7 | Duplicate-source majority download | Empty client connects to alpha and bravo, then downloads shared `ggoo`. | Metadata from both peers validates by majority/plurality, download completes once, and installed state matches the install flag. | +| S8 | Ambiguous metadata rejection | Two peers advertise the same game/version with conflicting file sizes. | Download fails with a `download-failed` event; no committed `version.ini` is left for the target game. | +| S9 | Missing game | Client asks for a game none of its peers can serve. | CLI reports a deterministic command failure and emits `no-peers-have-game`; no local files are created. | +| S10 | Shutdown and goodbye cleanup | Alpha and bravo are connected, then bravo shuts down. | Alpha receives peer loss/removal and remote games from bravo disappear. | +| S11 | Same identity reconnect | Bravo restarts with the same state dir but a new port, then alpha connects to the new address. | Alpha has one bravo peer entry with the updated address, not duplicate identities. | +| S12 | Transfer serving gates | A peer has a non-catalog, missing-sentinel, active-operation, or `local/` path request. | The serving peer declines metadata/data; covered by unit tests where timing is too small for a stable CLI race test. | + +## Run Log + +No scenario evidence recorded yet. diff --git a/justfile b/justfile index f84ec2e..61855a9 100644 --- a/justfile +++ b/justfile @@ -48,12 +48,45 @@ peer-cli-net: {{LANSPREAD_NET}} peer-cli-run NAME: peer-cli-net - mkdir -p "target/peer-cli/{{NAME}}/state" "target/peer-cli/{{NAME}}/games" + mkdir -p ".lanspread-peer-cli/{{NAME}}/state" ".lanspread-peer-cli/{{NAME}}/games" docker run --rm --init --network {{LANSPREAD_NET}} --name "lanspread-peer-cli-{{NAME}}" -i \ - -v "$PWD/target/peer-cli/{{NAME}}/state:/state" \ - -v "$PWD/target/peer-cli/{{NAME}}/games:/games" \ + -v "$PWD/.lanspread-peer-cli/{{NAME}}/state:/state" \ + -v "$PWD/.lanspread-peer-cli/{{NAME}}/games:/games" \ lanspread-peer-cli:dev \ --name "{{NAME}}" \ --games-dir /games \ --state-dir /state \ --catalog-db /app/game.db + +peer-cli-alpha: peer-cli-net + mkdir -p ".lanspread-peer-cli/alpha/state" + docker run --rm --init --network lanspread --name "lanspread-peer-cli-alpha" -i \ + -v "$PWD/.lanspread-peer-cli/alpha/state:/state" \ + -v "$PWD/crates/lanspread-peer-cli/fixtures/fixture-alpha:/games:ro" \ + lanspread-peer-cli:dev \ + --name "alpha" \ + --games-dir /games \ + --state-dir /state \ + --catalog-db /app/game.db + +peer-cli-bravo: peer-cli-net + mkdir -p ".lanspread-peer-cli/bravo/state" + docker run --rm --init --network lanspread --name "lanspread-peer-cli-bravo" -i \ + -v "$PWD/.lanspread-peer-cli/bravo/state:/state" \ + -v "$PWD/crates/lanspread-peer-cli/fixtures/fixture-bravo:/games:ro" \ + lanspread-peer-cli:dev \ + --name "bravo" \ + --games-dir /games \ + --state-dir /state \ + --catalog-db /app/game.db + +peer-cli-charlie: peer-cli-net + mkdir -p ".lanspread-peer-cli/charlie/state" + docker run --rm --init --network lanspread --name "lanspread-peer-cli-charlie" -i \ + -v "$PWD/.lanspread-peer-cli/charlie/state:/state" \ + -v "$PWD/crates/lanspread-peer-cli/fixtures/fixture-charlie:/games:ro" \ + lanspread-peer-cli:dev \ + --name "charlie" \ + --games-dir /games \ + --state-dir /state \ + --catalog-db /app/game.db