Protection Overview
Quick summary
Protecting a paid module means moving sensitive execution to a trusted server—not hiding JavaScript in a browser bundle. The CLI guides you through plan → review → apply → verify.
Track A examines existing code; Track B starts from a new feature specification. Both require explicit review and executed evidence.
The DevPay protect pipeline takes a paid-logic module and produces a partitioned client plus a generated loopback partition server — the paid code moves server-side, and the client bundle keeps only a forwarding shim. Everything runs through one entry point: the yp CLI (yp protect …), which delegates to the machinery in experiments/auto-protection/ rather than reimplementing it.
The pipeline
yp init scaffold devpay.json + .devpay/
yp protect plan analyze → spec (draft or approved) → ProtectionPlan
yp protect review human-readable §6.1 plan summary → human approves
yp protect apply AUTO→partitioner · AGENT→handoff · MANUAL_REVIEW→skip
yp protect verify executed checks → schema-valid evidence records2
3
4
5
Honest status words: planned ≠ applied ≠ verified — each stage produces distinct artifacts (plan.json → apply-report.json → evidence/*.record.json) and no stage upgrades a prior stage's claim.
Track A vs Track B
Two ways to feed the same planner/spec machinery (experiments/auto-protection/track-a, track-b):
| Track A | Track B | |
|---|---|---|
| Input | an existing module (--target m.mjs, optional --driver d.mjs) | a requirements document (--requirements reqs.json) |
| Spec source | spec/from-analysis.mjs draft derived from the analyzer's class verdicts | spec/from-requirements.mjs draft from the requirements |
| Apply | partitioner can execute AUTO decisions | handoff bundle only (plan → agent/human) |
The yp CLI exposes Track A through protect plan/apply; Track B's spec-from-requirements path exists in the toolkit (node track-b/run.mjs --requirements …) for requirements-first handoffs. In both tracks, every undecided spec field lands as REQUIRES_APPROVAL — drafts are never auto-approved.
Per-asset decisions
The planner emits one decision per spec asset:
| Decision | What apply does |
|---|---|
AUTO | Runs the partitioner — emits a generated partition server (imports runtime/) + partitioned client + manifest. |
AGENT | Emits a handoff brief for an agent — no code is produced by apply itself. |
MANUAL_REVIEW | Skipped — a human must decide. |
blocking_unknowns in the plan lists anything the analysis could not resolve; AUTO is also degraded to AGENT when the estimated server calls per operation exceed constraints.max_server_calls_per_operation.
Partition auth modes
Generated partition servers speak HTTP on loopback with one of two auth modes (--auth / protect.partition_auth):
dev-open— no auth; opt-in, loopback only. Development convenience.yp-license— the entitlement gate: the generated server verifies entitlement JWS + DPoP proof per call (the same wire contract as Licensing); requires a--license-seedfile.
Approval & binding model
- The plan is sha-bound to the exact spec object and target/driver file bytes (
plan_sha256,spec_sha256,target_sha256,driver_sha256). Apply re-hashes and refuses on drift (exit 2) — an approval binds those bytes, not a filename. - An approved spec (
draft:false, zeroREQUIRES_APPROVALmarkers) applies without override. --approveunder an unapproved spec allows handoffs only — anyAUTOdecision is refused (fail closed).- Through
yp-mcp,yetdapay_protection_applyadditionally requiresapproved:truebefore the CLI is even spawned.
What protection is not
Protection is cost-raising and server-dependency, not clone-proofing: a public client is still cloneable in principle (see Threat Model and Limitations). The dividing question for whether a function is protectable at all:
Does obtaining the value require the server to do something it would refuse to do for an unentitled requester?