Commit Graph
10 Commits
Author SHA1 Message Date
ddidderr 60fd7ba0c2 feat(peer)!: cut over to authenticated catalog sharing
Replace address-only trust and pushed peer state with installation identities,
SPKI-pinned QUIC, candidate-only discovery, and bounded responder-owned
protocol-8 pulls. The runtime now owns each network generation and all admitted
work through shutdown.

Add exact bundled content identities, reproducible manifest publishing,
capability-confined downloads, streaming BLAKE3 verification, quarantine and
retry, and crash-recoverable download and install transactions. Ship generated
fixture catalogs and fail closed when production manifests are absent.

The Tauri backend exposes durable sharing policy, redacted identity state, and
attempt-keyed transfer snapshots. Frontend consumption follows in the next
commit. Repository-wide test certificates and protocol-7 paths are removed.

BREAKING CHANGE: peers must use protocol 8 and exact catalog content artifacts;
protocol-7 frames and shared-certificate identities are no longer accepted.

Test Plan:
- `just test` -- passed on the completed stack (708 workspace tests)
- `just clippy` -- passed on the completed stack
- `just build` -- passed with fixture catalogs on the completed stack
- `just catalog-check-production` -- failed closed because the external
  production manifest corpus is absent
- `git diff --cached --check` -- passed
2026-08-10 13:59:18 +02:00
ddidderr 9c34efa705 feat(call-to-play): retain terminal outcomes
Keep complete running and cancelled histories visible for fifteen minutes so
peers retain the roster, chat, and outcome long enough to understand what
happened. Compact them to terminal tombstones afterward without charging
settled calls against the active-history limit.

Model running and cancelled as durable read-only frontend states, exclude
them from active badges, prune retired raw events, and document the lifecycle.
Add peer scenario S49 to prove a late joiner reconstructs a terminal call with
its roster and chat intact.

Test Plan:
- just fmt
- just clippy
- just test
- just frontend-test
- just build
- just peer-cli-tests S48 S49
- python3 -m py_compile crates/lanspread-peer-cli/scripts/run_extended_scenarios.py
- git diff --cached --check
2026-07-23 18:03:57 +02:00
ddidderr e5d70ae56f fix(call-to-play): acknowledge live replication
Raise the wire protocol to version 7 and add explicit Call to Play delivery
outcomes. Live requests now wait for an application acknowledgement, allowing
the sender to distinguish applied, duplicate, obsolete, incomplete, and
rejected updates instead of treating a successful write as acceptance.

Remove source-IP equality from actor verification. The receiver now requires
the envelope peer ID to be present in its known roster and requires every live
event actor to match that envelope. This matches the cooperative-LAN trust
model without misrepresenting the shared TLS identity as per-peer
authentication.

Transport failures, malformed responses, NeedHandshake, and NeedHistory each
trigger one asynchronous Hello/HelloAck resync. Rejections are logged without
retry, and local publication remains independent of remote availability.

Test Plan:
- `just fmt` -- passed
- `just clippy` -- passed
- `just test` -- passed
- `git diff --cached --check` -- passed
2026-07-23 17:49:01 +02:00
ddidderr be7ad2e560 refactor(call-to-play): merge histories atomically
Replace per-event insertion with a transactional batch merge. The store now
validates and deduplicates an entire history before committing it, rejects
conflicting event IDs without partial mutation, evaluates retention after all
batch events are present, and reports applied, duplicate, obsolete, and
missing-root outcomes explicitly.

Derive event identity from retained history instead of preserving an unbounded
ID set. Expired histories can therefore be restored by a complete Create plus
AddTime batch, while orphan actions request history and terminal tombstones
continue to reject stale resurrection. Capacity applies only to unresolved
history, allowing Start and Cancel to settle a full call.

Only retained events reach the UI or live broadcast path. Handshake and live
merge callers log invalid or incomplete histories without publishing events
that compaction discarded.

Test Plan:
- `just fmt` -- passed
- `just clippy` -- passed
- `just test` -- passed
- `git diff --cached --check` -- passed
2026-07-23 17:44:03 +02:00
ddidderr d58307c328 fix(call-to-play): compact expired snapshots
Expired call histories were removed on the next store insertion, so an otherwise
idle peer could continue carrying stale payload through handshakes after the
five-minute UI retention ended.

Run the same inactive-call compaction before local and handshake snapshots. This
makes the expiry boundary exact without trimming any event from an active call.

Test Plan:
- `just fmt` -- passed
- `just clippy` -- passed
- `just test` -- passed, 147 peer tests
- `git diff --cached --check` -- passed
2026-07-21 22:59:48 +02:00
ddidderr 383e8f4855 fix(call-to-play): resync after live delivery failure
A failed fire-and-forget event left one peer's active call state divergent until
some later discovery or reconnect happened. During a LAN party that could leave
different players looking at different rosters or chat.

Fall back to the existing bidirectional handshake whenever a live Call to Play
send fails. Its active-history exchange heals both sides immediately when the
failure was transient. Document the related wall-clock synchronization
assumption for deadline and countdown presentation.

Test Plan:
- `just fmt` -- passed
- `just clippy` -- passed
- `just test` -- passed, 147 peer tests
- `just peer-cli-tests S48` -- passed
- `git diff --cached --check` -- passed
2026-07-21 22:58:19 +02:00
ddidderr cc7dacf6c3 fix(call-to-play): expire elapsed calls clearly
Deadline completion previously shared the green Ready presentation with a full
roster and remained visible forever. An abandoned call therefore looked ready
to launch and required its creator to return and cancel it.

Give elapsed calls a distinct Time's up state and a five-minute grace period in
which the creator can start or extend them. After that, both the reducer and
peer store remove the call as a unit. Filled calls remain ready until their
deadline, and active calls continue to retain complete history for late joiners.

Test Plan:
- `just fmt` -- passed
- `just clippy` -- passed
- `just test` -- passed, 147 peer tests
- `just frontend-test` -- passed, 22 tests
- `just build` -- passed
- `git diff --cached --check` -- passed
2026-07-21 22:56:02 +02:00
ddidderr 4b7725db16 fix(call-to-play): compact terminal histories
The 4,096-event store retained every completed call forever and local commands
only reported that they reached the queue. Once the bound was reached, GUI
actions could therefore fail with no user-visible result. The CLI snapshot wait
could also be satisfied by an unrelated live event.

Keep the complete event and chat history for every active call so late joiners
receive full context. When the creator starts or cancels a call, replace its
history with a single terminal tombstone; this bounds retained payload while
still healing peers that missed the live terminal action. Publish commands now
reply with the actual store result, and CLI snapshots use a direct reply.

Test Plan:
- `just fmt` -- passed
- `just clippy` -- passed
- `just test` -- passed, including full-cap terminal compaction
- `just build` -- passed
- `just peer-cli-tests S48` -- passed
- `git diff --cached --check` -- passed
2026-07-21 22:48:19 +02:00
ddidderr 29eacabcc0 fix(call-to-play): key actors by stable peer identity
Participant maps and creator authorization previously used display names, so
two peers left at the default Commander name collapsed into one participant
and could exercise each other's creator controls through the normal client.

Carry a stable actor_id separately from actor_name. The peer overwrites actor_id
on every local publish, and live event envelopes are accepted only when the
known peer, source, and event actor match. The frontend keys participants and
authorization by actor_id while retaining actor_name for display. This follows
the trusted-LAN model and is not cryptographic authentication against a hostile
peer.

Test Plan:
- `just fmt` -- passed
- `just clippy` -- passed
- `just test` -- passed
- `just frontend-test` -- passed, 21 tests
- `just build` -- passed
- `just peer-cli-tests S48` -- passed
- `git diff --cached --check` -- passed
2026-07-21 22:40:59 +02:00
ddidderr 0f53bc4b78 feat(call-to-play)!: coordinate game sessions across peers
Implement the launcher design as a production peer-to-peer feature. Call to
Play actions are immutable, validated events broadcast over the existing QUIC
control channel, deduplicated in a bounded in-memory history, and exchanged in
Hello/HelloAck so late joiners reconstruct current calls.

Add the Tauri bridge and modular launcher surfaces for play-now and scheduled
calls, check-in, readiness buffers, role-aware controls, chat, tickers, and
actual caller launch. A deterministic frontend reducer derives presentation
state from replicated history. Extend the JSONL peer harness with publish/list
commands and a three-peer live-delivery and late-join scenario.

This intentionally raises the only supported wire protocol from version 5 to
version 6; older builds are not supported. Document the transport architecture
and exclude generated peer-test state from Docker build contexts.

Test Plan:
- `just fmt` -- passed
- `just clippy` -- passed
- `just test` -- passed
- `just frontend-test` -- passed, 20 tests
- `just build` -- passed
- `just peer-cli-tests S2 S48` -- passed
- `git diff --cached --check` -- passed
2026-07-21 22:30:11 +02:00