feat(plantare): PlantareService — orchestrate the signed handshake

The app-layer driver that turns local intent into a signed proposal,
counter-signs or declines incoming ones, and reconciles every move into
the local ledger. Cryptography and wire format stay in commons_core;
this owns persistence and orchestration.

- propose(): builds + self-signs a PlantarePledge, records the local row
  (remoteState=proposed, my stub) and sends it. Direction maps to
  debtor/creditor: iReturn = I received and owe, owedToMe = I gave.
- accept(): counter-signs the exact in-hand proposal (verified) and sends
  the doubly-signed copy back, closing the row.
- decline(): notifies the proposer and marks the row declined.
- ingest(): verifies stubs before storing — a bad-signature proposal or a
  half-signed "accept" is dropped; proposals not addressed to me are
  ignored. Pending proposals held in memory keyed by pledge id (relay
  redelivers on reconnect), so accept signs the verified payload.

Wired into DI + Bootstrap alongside the inbox/sync listeners and torn
down/rebuilt on identity switch. SocialSession now exposes the transport.

Tests: full propose→accept close, decline, and the three drop paths with
a records-only transport + real repos. services/data green.
This commit is contained in:
vjrj 2026-07-14 11:07:58 +02:00
parent bec0f78fa1
commit 2e25e34d11
5 changed files with 529 additions and 3 deletions

View file

@ -99,6 +99,7 @@ class SocialSession {
ratings = NostrRatingTransport(_channel),
reports = NostrReportTransport(_channel),
profile = NostrProfileTransport(_channel),
plantares = NostrPlantareTransport(_channel),
sync = NostrSyncTransport(
_channel,
namespace: kInventorySyncNamespace,
@ -114,6 +115,10 @@ class SocialSession {
final ReportTransport reports;
final ProfileTransport profile;
/// Bilateral signed Plantaré handshake (propose/accept/decline), private
/// end-to-end over the shared connection.
final PlantareTransport plantares;
/// Device-to-device inventory sync for THIS identity's own devices.
final SyncTransport sync;