Concepts
Four ideas structure everything in these docs: protection, licensing, payments, and trust boundaries.
Protection
The protect pipeline moves paid logic off the client. Instead of shipping paid.mjs inside a buyer's bundle, the pipeline splits it into:
- a partitioned client that keeps the module's public API and forwards calls, and
- a generated partition server that runs the paid functions on loopback (or wherever the seller hosts it), speaking HTTP with an auth mode of
dev-open(loopback dev only, no auth) oryp-license(the entitlement gate described under Licensing).
Two tracks feed the same plan/apply/verify machinery (experiments/auto-protection/):
- Track A — analyze an existing module, draft a spec from the analysis, plan, apply.
- Track B — start from a requirements document, draft a spec from it, plan, hand off.
Decisions are per-asset: AUTO (partitioner executes), AGENT (handoff brief — no code is produced), MANUAL_REVIEW (skipped, human decides). See Protection Overview.
Licensing
A license is the durable record (lic_… row, NG-… key) minted at purchase. On top of it sits the proof-of-possession (PoP) plane:
- Activation — the client presents
{key, product_id, public_jwk}; the authority binds a device slot tojkt(a DevPay-specific double-hash of the RFC 7638 JWK thumbprint — not RFC 9449) and returns a short-lived entitlement (JWS,expires_in: 120). - Entitlement —
iss/lic_id/product_id/features/jkt_bound/cnf.jkt/iat/expsigned by the platform key. Presented asAuthorization: Entitlement <jws>. - Proof (DPoP-style) — every gated call carries a fresh JWS proof
{htu, htm, iat, jti, h, jwk};jtinonces are consumed atomically so replay fails closed. - Capability — a 60-second one-time execution token per feature; reuse →
409 CAPABILITY_CONSUMED. - Revocation — the license row is re-queried on every guarded call;
revoked/suspended/expired/INVALID_STATUSbeats any still-valid token.
The contract is DevPay-specific wire v1 — no version negotiation exists (known-limitations §3.2). The single normative reference is the interface contract matrix.
Payments
The commerce spine is deliberately conservative:
- Checkout is idempotent (
idempotency_key) and atomic — the mock provider path writes order + payment + subscription + license + ledger + audit + outbox in one D1 batch.tosscreates apendingorder confirmed via/checkout/confirmor the signature-verified webhook (body never trusted; PG state is refetched). - Refunds are pre-recorded
refund_attempts(attempted→succeeded/failed/needs_review), then PG cancel, then ledger/license compensation.needs_reviewis a manual-ops state, not an error the system hides. - Settlement is an accrual run (
POST /settlements): paid un-settled orders are claimed via conditional UPDATE, fees are computed fromseller_settingsrates, and apendingST-YYYY-NNNNsettlement is written with ledger + audit entries. - Donations are sandbox-only (
donationstable,status: "sandbox") — structurally separate from orders/payments; no real money moves.
There is no real PG capture in this wave. PAYMENT_LIVE_ENABLED=false and TEST keys only; Portone returns 503 PAYMENT_PROVIDER_UNAVAILABLE.
Trust boundaries
Three parties with non-overlapping responsibilities (trust model):
- DevPay (platform) — license + entitlement authority. Meters only what it observes (
license_usagerows come from DevPay-hosted/licenses/execute); BYOS executions inside a seller's own server are structurally invisible to the platform. - Seller — owns the software, the feature namespace (
products.features_jsonis the sole entitlement source of truth), and the BYOS enforcement server. A seller can remove client-side checks in their own product — enforcement bounds the buyer-facing contract, it cannot make a seller's machine tamper-proof. - Buyer — holds a license key and a device keypair. The private key is a non-extractable WebCrypto
CryptoKey— but a determined buyer controls their own environment; protection raises cost, it does not produce absolute clone prevention (deliberate exclusion, known-limitations §5).
Two operational boundaries matter equally:
- The protect pipeline executes workspace code.
yp-mcpand the analyzer are not sandboxes; point them only at workspaces you trust. - Credentials never cross into public surfaces. Seller tokens go only to seller endpoints;
/public/**calls are always unauthenticated, and onlypublic_idis safe to embed in visitor-facing code.