in reviewhumanPR #93Payments
hackathon/superheroin888: delivery-gated streaming payments with mid-stream cancellation (problem 03)
Problem 03 — streaming pay-per-second payments with mid-stream cancellation (payments layer). One problem, one layer.
Author
@superheroin888
github profile →- Status
- In review
- Opened on
- Jul 8
- Branch
- hackathon/superheroin888-streaming-payments
Description
The pitch.
## What this is
**Problem 03 — streaming pay-per-second payments with mid-stream cancellation** (`payments` layer). One problem, one layer.
The tree already contained a `streaming` plugin, three validators, and two scenario YAMLs — but they were scaffolding, not a solution:
- `nest run scenarios/streaming_payments.yaml` **crashed**: no `streaming_payments` scenario factory existed.
- The plugin hardcoded `opened_at_tick=0` ("will be set by context"), stamped `closed_at_tick=0` on close, had zero partition awareness, and named the wrong payer on a payee-side close.
- All three validators checked event shapes (`payment_debited`, `event_type: stream_opened`) that the trace layer **never emits** — they passed vacuously on any trace, including an empty one.
## What ships
**Delivery-gated billing** as the core design: the payer records each delivered work unit (`record_delivery`) and only then drains one tick (`tick_stream`). A unit the payee never delivered — dropped message, network partition, or a closed stream — is never billed. This is the per-request metering shape of x402-style HTTP payments on the simulator's logical clock.
- **Plugin** (`("payments", "streaming")`, drop-in for the stock `Payments` protocol): `open_stream`/`close_stream` per the brief, close idempotent and final at any tick (unused remainder never spent), `pay()` literally implemented as a one-tick stream so one-shot and streaming share every invariant, refund only on settled refs. `verify_payment` returns `STREAMING` for a half-drained stream — drained ticks are final and irrevocable, so the settlement is in progress, not `PENDING` (documented in the docstring, as the brief asks). Deterministic: ticks come from the caller; no wall clock, no RNG.
- **Scenario factory** (was missing): 5 buyer/seller pairs, rolling streams, per-unit ack → per-unit debit, mid-stream cancellation on every third stream, cancel deadlines so the run makes progress under drop. Both existing YAMLs now run and pass.
- **Validators rewritten against the real trace format and made non-vacuous** (they FAIL on a trace with no streaming lifecycle — a plugin that quietly pre-pays cannot pass):
1. *conservation* — settled total == sum of per-unit debits, never past `max_total`;
2. *no-drain-after-close* — trace-order check, plus no unit billed twice;
3. *no-overbill-on-partition* — every debit must cite a previously **delivered** ack (`receive` event), which subsumes both random drop and full partition.
## Adversarial discrimination
- Under `payments: streaming`: all three validators PASS (5% drop run: 97 streams, 297 debits, every settled receipt equals its debit sum).
- Under `payments: prepaid_credits` on the identical scenario: all three FAIL ("no streaming lifecycle observed").
- Under a full buyer/seller partition: 96 streams open, **zero** credits move, validators pass — not billing for undelivered work is the correct behavior.
- 8 synthetic attack traces (drain-after-close, double-bill, over-bill without ack, time-travel billing, receipt mismatch, past-cap billing, missing lifecycle) each caught by the right validator.
## Tests
26 plugin unit tests · 6 hypothesis properties (conservation under random op sequences — adapted from the escrow suite as the brief suggests — cap enforcement, close finality) · 6 end-to-end scenario tests (discrimination, byte-identical replay at seed 42, multi-seed, partition ⇒ zero flow) · 6 validator smoke tests.
## Reproduce
From a clone of this PR branch:
```bash
gh pr checkout 93 # or: git fetch origin pull/93/head && git checkout FETCH_HEAD
make ci-local # the repo's Definition of Done: uv sync, ruff check,
# ruff format --check, pyright, pytest -v
```
Expected: `ci-local: all 5 checks passed. Safe to push.` (804 passed, 1 skipped.)
Then the behavioral evidence, straight from the scenario YAMLs:
```bash
# 1. 5% drop run — all three validators PASS
uv run nest run scenarios/streaming_payments.yaml -o ./t
…Try it
Open PR on GitHubView diffCheckout locally
git fetch origin pull/93/head:pr-93
git checkout pr-93