Skip to content

feat(license): lease-model client — offline-verifiable short tokens w/ auto-refresh - #361

Open
runyourempire wants to merge 1 commit into
mainfrom
feat/license-lease-client
Open

feat(license): lease-model client — offline-verifiable short tokens w/ auto-refresh#361
runyourempire wants to merge 1 commit into
mainfrom
feat/license-lease-client

Conversation

@runyourempire

Copy link
Copy Markdown
Collaborator

Consumes the deployed lease server (/api/license/refresh, PR #357) to deliver the at-scale licensing architecture: offline-verifiable short-lived entitlement tokens, auto-refreshed, with revocation driven live by Stripe.

How it works

  • User activates once with a stable 4DA-LIC-… refresh credential.
  • App exchanges it for a signed 4DA-… entitlement token (verified offline by the existing verify.rs — unchanged) and re-runs the exchange on startup + every 6h.
  • Revocation: a cancel/refund reflected live in Stripe → next refresh denies → downgrade. Online latency ≤6h; offline users keep working until the token's embedded expiry + the existing 30-day activation grace.
  • Scale: validation is offline (infinite, $0, no spike failure mode); refresh is ~1 call/user/6h.

Safety invariant (unit-tested)

Network error / HTTP 5xx / malformed response never downgrade a paying user (KeepCurrent). Only an authenticated "not entitled" revokes. Durable credential stored in the keychain (survives a settings.json license-block wipe — the recurring "Signal→Free" bug class) with settings rehydration.

Changes

  • settings/license/lease.rs (new) — refresh client + classify_response (unit-tested).
  • settings/types.rsLicenseConfig.refresh_key: Option<String> (serde default, zeroized, redacted).
  • settings_commands_license.rsactivate_license matches 4DA-LIC- before the 4DA- branch.
  • app_setup.rs — 6-hourly refresh task.
  • verify.rs / reconcile / gating: untouched. Legacy 4DA-<sig> + Keygen keys still work. Additive, no migration.

Verification

  • cargo test settings::license27/27 pass (6 new lease tests incl. "5xx never revokes"; all reconcile/gating/serde-roundtrip tests still green).
  • cargo fmt clean; clippy adds zero new warnings in changed files.

⚠️ Merge gate

Per intelligence doctrine, this ships behind a 7-day founder dogfood on a RELEASE build before any customer. The delivery switch (success page / recovery returning the 4DA-LIC credential instead of the legacy long token) is a deliberate follow-up, sequenced after this client is in users' hands so no buyer ever receives a credential an older app can't use.

🤖 Generated with Claude Code

…hort tokens

Consumes the deployed lease server (/api/license/refresh). The user activates
once with a stable `4DA-LIC-...` refresh credential; the app exchanges it for a
short-lived, OFFLINE-verifiable `4DA-...` entitlement token and re-runs the
exchange on startup + every 6h, so revocation (a cancel/refund reflected LIVE in
Stripe) reaches online users within the interval while offline users keep working
until the token's embedded expiry.

- settings/license/lease.rs (new): is_refresh_credential, refresh_entitlement,
  maybe_refresh_lease, RefreshOutcome. Pure classify_response() is unit-tested.
  INVARIANT: network/5xx/malformed NEVER downgrade a paying user (KeepCurrent);
  only an authenticated "not entitled" revokes. Durable credential stored in the
  keychain (survives a settings.json license-block wipe) with settings rehydration.
- settings/types.rs: LicenseConfig gains `refresh_key: Option<String>`
  (#[serde(default)], zeroized on drop, redacted in Debug). All existing struct
  literals updated.
- settings_commands_license.rs: activate_license matches `4DA-LIC-` BEFORE the
  `4DA-` signed-token branch; stores credential + first token, slides activated_at.
- app_setup.rs: spawns the 6-hourly refresh task after startup validation.
- Verification path (verify.rs), reconcile, gating: UNCHANGED — the token is the
  same signed 4DA- format they already handle. Legacy 4DA-<sig> + Keygen keys
  still activate. Additive, no migration.

Verified: cargo test settings::license 27/27 pass (6 new lease tests incl.
"5xx never revokes"; all reconcile/gating/serde-roundtrip tests still green);
cargo fmt clean; clippy introduces zero new warnings in changed files.

GATE: ships behind a 7-day founder dogfood on a RELEASE build (doctrine) before
any customer. Delivery switch (success page/recovery returning the 4DA-LIC
credential instead of the legacy long token) is a follow-up, sequenced AFTER
this client is in users' hands.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PNQqR59PomAowHWXJoAzha
@vercel

vercel Bot commented Jul 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
4da-home Ready Ready Preview, Comment Jul 20, 2026 5:34pm

Request Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant