All checks were successful
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Successful in 3m27s
OpenPay now runs a metered charge on card and instant rails and asks a gate to bound it and record the measurement with it. Its reference gate does the first and keeps a book. `JcpGate` is the gate that does both, and adds what a payment rail has no field for. **A second ceiling.** Each reservation is a hold on a grant carrying a money ceiling and a joule ceiling, enforced independently with no rate between them. A charge the money allows is refused when the energy the operator allowed does not, and the receipt names which ceiling bound — a statement a card network has no way to make. **A signed measurement.** Every capture and every resolution seals a receipt committing to the amount that moved, the rail's own reference for it — the acquirer's payment id, the instant rail's transaction id — and the joules measured, at the grade of the meter that produced them. A different amount, reference, figure or grade is a different receipt. A grade is carried as stated and never upgraded: an unrecognised claim about how a figure was obtained is taken as the weakest grade, not the strongest, and a unit this profile does not meter in is refused rather than read as joules. **And a mandate becomes the ceilings.** AP2 payment mandates were evaluated in OpenPay and went nowhere; the mandate-to-limit path was two halves. `mint_from_mandate` joins them. The mandate is evaluated in full first — payee, instrument, window, recurrence, reference, and any constraint not understood refuses — with the session's maximum read as the amount, since a metered charge is admitted on its upper bound. Then `payment.budget` less what history shows spent is the session ceiling; `payment.amount_range.max` bounds each single reservation, and stands as the session ceiling too where there is no budget, because a mandate with no budget authorizes one payment and not a series; and a mandate that bounds no money mints nothing. The joule ceilings come from the operator alone: the mandate has authority over the money and none over the energy. Nothing that verified the mandate, no gate — the amounts read are about to be enforced as if the user had signed them. The gate is tested through the `MeteredGate` trait, in the order the rail drivers call it, and the drivers are tested where they live. An earlier draft hosted fake acquirers here, which pulled the rails' whole HTTP stack into this workspace's lockfile — eleven hundred lines to hold two test doubles. The trait is the contract between the two, so that is what each side tests against. The capability document names the code behind each rail projection and states the ordering rule both follow when a gate decision and a rail operation disagree. Co-Authored-By: Claude <[email protected]>
23 lines
1.2 KiB
TOML
23 lines
1.2 KiB
TOML
[package]
|
|
name = "jcp-openpay"
|
|
version.workspace = true
|
|
edition.workspace = true
|
|
license.workspace = true
|
|
repository.workspace = true
|
|
description = "OpenPay profile of JCP — a metered-settlement gate for the card and instant rails. Each reservation is a dual-ceiling hold (money from the payment, joules from the operator, no rate between them), each capture and each resolution is decided outside the model, and every one seals a receipt binding the amount that moved to the energy measured for it. The rails keep their transport; JCP adds the second ceiling and the signed measurement."
|
|
|
|
[dependencies]
|
|
jcp-schema = { workspace = true }
|
|
jcp-grant = { workspace = true }
|
|
jcp-runtime = { workspace = true }
|
|
jcp-receipt = { workspace = true }
|
|
ed25519-dalek = { workspace = true }
|
|
serde_json = { workspace = true }
|
|
# The gate contract only — not the rail drivers or their HTTP stack.
|
|
op-metered = { path = "../../../../openpay/crates/op-metered", default-features = false }
|
|
op-core = { path = "../../../../openpay/crates/op-core" }
|
|
# The agent-mandate reader: a verified payment mandate becomes this gate's money ceiling.
|
|
op-agentic = { path = "../../../../openpay/crates/op-agentic" }
|
|
|
|
[lints]
|
|
workspace = true
|