[Hackathon] chainaim-nisha : Outcome-Verified Settlement: per-tick payments gated by delivery, integrity, and conformance truly allowing for outcome versus tokens#61
Open
chainaim-nisha wants to merge 1 commit into
Conversation
|
Thanks for this, the engineering is strong. Verified locally on the PR head
Holding merge on scope, not correctness. This adds a |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Outcome-Verified Settlement: per-tick payments gated by delivery, integrity, and conformance truly allowing for outcome versus tokens
Problem: 03 — Streaming pay-per-second payments with mid-stream cancellation
Layer:
paymentsRegistered as:
("payments", "outcome_verified_settlement")Persona:
settlement-protocol-standards-engBranch:
hackathon/settlement-protocol-standards-eng-outcome-verified-settlementVisual explaination of PR Solution
https://incredible-baklava-420ffb.netlify.app/
Motivation
The spec's own frame for Problem 03 is time-metered billing: bill while the stream
is open, stop billing on close or partition. That's a real requirement and this PR
satisfies it. But time-metered billing only answers "did the clock tick" — it says
nothing about whether the metered unit was actually delivered, delivered intact, or
delivered correct. This PR adds a pluggable settlement gate so a tick can be
billed on any of three cumulative disciplines:
bills once the seller acks it), so it's a drop-in, not a rewrite;
declared checksum before a tick is billed, catching corruption in transit;
the buyer's committed acceptance criterion for that specific unit — catching a
seller that delivers a different, real unit's content with an honest checksum
of what it actually sent. Integrity alone cannot see this: the checksum is
honest, the content is just wrong.
The name
outcome_verified_settlementis now literally backed by code: an L3 passmeans delivered AND intact AND conforming, not merely "the seller's own checksum
claim was self-consistent."
The verification ladder
AckReceivedGate(default)ChecksumGate(gate: checksum)EvaluatorGate(gate: evaluator,criterion: reference_match)Each rung catches exactly one failure class the rung below is blind to.
EvaluatorGatecomposesChecksumGateinternally (require_integrity=Truedefault) and short-circuits on an integrity failure before the criterion ever runs.
The proof that L3 is not redundant with L2 — an honestly-checksummed reply to the
wrong unit that passes integrity and fails conformance — is isolated in
test_outcome_verified_settlement_b5_checksum_passes_criterion_failsand re-proventhrough the real driver in
test_outcome_verified_settlement_b6_nonconform_checksum_is_honest_at_failing_seq.json_schemaandartifact_matchare two additional, real, independentlyunit-tested criteria (
test_outcome_verified_settlement_b7_criteria.py) —deliberately not yet wired through
Gate.from_name/scenario YAML, since they needparameters (
required_fields,expected_sha256, etc.) the wire-level configdoesn't carry in this iteration.
reference_matchis the only criterion reachablefrom a scenario today;
criterion_hash-on-wire is roadmap, not this PR.What ships
("payments","outcome_verified_settlement")nest_core/plugins.py_BUILTINS+pyproject.tomlentry pointnest.plugins.paymentsopen_stream(to, rate_per_tick, max_total, ref) -> StreamHandleoutcome_verified_settlement.py::OutcomeVerifiedSettlement.open_streamclose_stream(ref) -> Receipt, deterministic, any tick, unused remainder never spentoutcome_verified_settlement.py::OutcomeVerifiedSettlement.close_streammax_totaloutcome_verified_settlement.py::OutcomeVerifiedSettlement.advancepay/refund(existingPaymentsprotocol) still workpay== a one-tick stream that drains the full amountscenarios_builtin/chainaim/gates.py—Gate.from_name,AckReceivedGate,ChecksumGate,EvaluatorGategates.py—reference_match(wired),json_schema/artifact_match(unit-tested, not wired)scenarios_builtin/chainaim/outcome_verified_settlement.pynest_core/chainaim/outcome_verified_settlement_validator.pyscenarios/outcome_verified_settlement{,_overbill,_degrade,_degrade_billbug,_nonconforming,_nonconforming_billbug,_rolling}.yamlThreat model
max_total; no metered tick after the close tick; every debited unit is credited in the same step (conservation), enforced atomically inadvancevalidate_outcome_verified_settlement_no_drain_after_close; conservation is proven by ahypothesisproperty test (the trace carries no balances, so per-tick debit==credit is proved at the plugin boundary, not re-derived from the trace)drained ≤ rate × acks receivedvalidate_outcome_verified_settlement_no_overbill; thebill_on_send: truevariant (_overbill.yaml) is the runnable negative controldrained ≤ rate × pass-verdicts(content gate only)validate_outcome_verified_settlement_no_overbill_on_failed_verification;_degrade_billbug.yaml(L2) and_nonconforming_billbug.yaml(L3) are the runnable negative controlspassdespite a checksum that doesn't actually matchgate:passrequires the recomputed checksum to match the declared one, re-derived independently from the trace, never trusting the gate's own claimvalidate_outcome_verified_settlement_verdicts_match_committed_criterion. Scope, stated not hidden: integrity-honesty only, one-directional — a legitimate L3failis never flagged, only a dishonestpassis, because the trace doesn't yet commit which criterion was configured (roadmap:criterion_hashon the wire)Every validator reconciles from the trace, never from the plugin's own accounting —
the threat modeled is precisely a plugin whose internal accounting is wrong.
Trace grammar
Unchanged since L1+L2: L3 (nonconforming) units reuse this exact grammar — no new
trace lines were needed for conformance-gating; only the bytes the seller sends
differ, not the message shape. The default (L1) path still emits a trace
byte-identical to the pre-gate scenario.
Design tradeoff: no custody, unit-capped credit risk instead
This PR moves funds buyer→seller directly per verified tick — no escrow account, no
locked capital, no arbiter. The tradeoff: the seller carries per-unit credit risk
(the buyer could be insolvent at the moment of
advance()), which an escrow modelwould eliminate via a solvency guarantee. This PR's position: that risk is detected
on the very next tick and capped at one unit's rate, which is a better trade than
locking working capital for the full stream duration — for small, frequently-verified
units. For large, one-shot, subjective transfers, escrow is the right tool; this PR
doesn't compete there.
How is this solution PR unique and different from other PR's and addresses industry need for pay for outcome versus tokens ,hence not a duplicate
The spec's suggested key,
("payments","streaming"), is already registered by amerged upstream PR (#21) that bills on the clock
while a stream is open. This PR registers a distinct key,
outcome_verified_settlement,because the contribution is a different invariant —
billed ≤ rate × verified units,not
billed while stream is open— and the default gate reproduces the merged plugin'sdelivery-gated behavior byte-for-byte, so this is a drop-in verification upgrade,
not a competing reimplementation. The open escrow submissions (#7 HTLC, #38
arbitrated escrow, #41 EMPIC evidence-gated escrow) occupy the custody/arbitration
design space — funds locked up front, released on acceptance or arbitration; this
PR deliberately occupies the opposite corner: no custody, direct per-unit
settlement, each unit verified before it bills thus making it more practical for agentic delivery Versus payments (see the design-tradeoff section
for when each model is the right tool).
("payments","streaming")("payments","outcome_verified_settlement")billed ≤ rate × verified units(outcome-metered)Gateseam: L1 delivery / L2 integrity / L3 conformance..._b11_invariant_not_vacuous.py)Verification
Observed on the exact branch under review (full workspace, no path filter):
839 passed, 1 skipped, 1 deselected, 0 failed;
ruff checkclean ("All checkspassed!");
ruff format --checkclean (187 files already formatted);pyright0 errors / 0 warnings / 0 informations;
uv syncresolved 89 packages clean.Rolling streams are covered end-to-end in
test_outcome_verified_settlement_b10_rolling.py(unique per-cycle refs, 4/4validators on the rolling trace, per-cycle cap independence, failed-verdict-closes-
cycle-next-still-opens, a partitioned buyer that opens once, never rolls, and
bills nothing, same-seed determinism, and a regression that the base scenario
stays on the five legacy refs). The comparative discipline proof lives in
test_outcome_verified_settlement_b11_invariant_not_vacuous.py: the identicaldelivered-unit sequence passes all four validators under outcome-verified billing
and fails exactly
no_overbill_on_failed_verificationunder clock/deliverybilling — the baseline is correct by its own spec (it satisfies
no_overbillexactly), so the new invariant is discriminating, not vacuous.
Extension in phase2
In phase2, the solution will be extended with more real-world scenorios and usecases .
Visual explaination of PR Solution
https://incredible-baklava-420ffb.netlify.app/