Skip to content

Decouple payments into operator adapters and metered credits - #115

Merged
dskvr merged 8 commits into
fix/provider-neutral-deploymentfrom
feat/payment-adapters
Nov 10, 2026
Merged

dskvr merged 8 commits into
fix/provider-neutral-deploymentfrom
feat/payment-adapters

Conversation

@dskvr

@dskvr dskvr commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

The CVM now meters integer credits while operators own payment implementations, verification, sale prices and currency conversion. Deployments select one or more external adapter modules or payment-free access with an explicit npub allowlist and request limit. The workspace discovers installed methods and presents payment selection.

The existing Lightning/NWC and Cashu implementation, provider stack and dependent regression suites move to an operator-owned package. Typed compatibility entrypoints preserve existing callers and settlement identities when that implementation is installed. Existing balances, keys, holds and audit records are preserved. Modern top-ups request credits; legacy source-amount calls remain supported.

The service funding configuration changes explicitly. Deploy the application with its selected adapter package and updated configuration, or configure free access. The additive source-identifier migration broadens credit sources without rewriting history. Downgrading to pre-extraction code requires a compatible snapshot; deployment tooling refuses an implicit schema downgrade.

Validation includes signed ContextVM tests for multiple adapters and free admission, grant replay/ownership/rounding tests, PostgreSQL concurrency and upgrade checks, adapter payment/restart tests, and real local Cashu/NWC, generation and resume integration. Both TypeScript projects pass. Historical OTel approval remains scoped to its original manifests; tests retain that fail-closed behavior after dependency extraction.

This PR is stacked on #114. Homelab deployment verification is recorded in the operator repository; no private infrastructure is required to understand or use the public adapter contract.

Live rollout: both existing deployments use application 9f2a1fa with the pinned private adapter. Service keys and databases were reused. The original homelab workspace passes private-adapter funding, bounded real ChatGPT generation, interactive sandbox preview, and old/new artifact reopen. The separate API service passes Lightning/Cashu/replay checks; its full generation flow is blocked by its configured OpenAI credential returning HTTP 401 (zero spend). Exact infrastructure evidence remains in the operator repository.

Final isolated end-to-end rerun: 167 passed, 1 skipped, 0 failed across 47 files (real local payment rails, module loading/restart, generation and resume).

@dskvr
dskvr merged commit a5fa919 into fix/provider-neutral-deployment Nov 10, 2026
13 checks passed
dskvr added a commit that referenced this pull request Nov 10, 2026
* feat(service): provider-neutral service composition and canonical migrations

Boot the normal entrypoint from a mounted config and secret files, using the
same funding, metering, worker, preview and publication classes as the working
service. Migrations become an explicit command with an immutable realm marker.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(service): container stack with gVisor build engine and worker boundary probe

Run untrusted builds and publication screenshots under runsc inside a private
engine. The probe checks the real runtime: identity, capabilities, read-only
root, denied network, and a complete conformance build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(funding): return payable Lightning requests and add test-realm rails

A pending Lightning top-up now returns its BOLT11 request to the verified
requester, so a real wallet can pay it. Test realm gets a FakeWallet mint and
receive-only NWC wallet, operated outside the service.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(service): end-to-end flow driver, backup, isolated restore test and model pricing

Drive the real user flow over public origins with a user-held key. Snapshot
the database and storage into a volume the host backup collects, then restore
it into an unrouted instance and verify identity, rows, artifacts and reopen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(service): gate wallet and service on a healthy relay; real Lightning funding in the UI

Document the deployment, backup, restore and rollback procedure and mark the
withdrawn Google runbooks historical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(service): restored relay directory is owned by the relay user

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(service): require two Cashu mints, add a second test mint, report validation paths

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(pricing): input ceiling covers the full authoring guidance

The request guard compares encoded bytes to input tokens; 61 KB of guidance
exceeded the 48k ceiling, so every request was refused before dispatch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(model): log a bounded error code when a dispatch outcome is uncertain

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(model): explicit OpenAI refusals settle as non-acceptance; test-realm deterministic adapter

A 4xx refusal (for example insufficient_quota) left the action usage_unknown
with held funds. It now settles at zero charge; 5xx and transport failures
still reconcile before retry. The test realm may select a deterministic model.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(flow): reconcile settled funds; open sessions hold their remaining cap

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(flow): preview descriptors report status

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(service): explicit per-host resolver for outbound names

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(publication): the service's own public relay is reached over its internal address

Other user relays must still resolve to public addresses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(publication): treat the internal service relay as configuration

A private stack relay name failed user-relay validation outside the
per-relay error handling and aborted the whole announcement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(service): restore starts every test rail; startup reports error class and code

Add coverage for 30-day pending-action expiry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(restore): live data modes and an enforced ledger invariant; service CI

The restored relay could not traverse a 0700 data directory. Restores now fail
unless every account's ledger equals its settled projection. Add a service
workflow and update entrypoint invariants for the provider-neutral boot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(restore): repair verify-restore ledger check

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(restore): purge earlier isolated instances by compose label

A stale environment file made compose down fail silently, so later restores
reused containers bound to a deleted data directory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(model): parse the rejection fixture intent through its schema

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(quick-261101-pnd): record provider-neutral service deployment evidence

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(model): tell the model the template compiles with unused-variable checks

Paid gpt-5-mini sources were rejected at verify for unused catch bindings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(quick-261101-pnd): record paid generation evidence

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: package service runtime and preserve startup diagnostics

* fix: create image scratch directory before browser installation

* fix: separate portable service from private deployment configuration

* fix: distinguish provider refusals from artifact failures

* fix: recover compiler failures with one metered correction

* fix: use Paja host services in applet previews

* feat: give napplet generation skills and authoring tools

* test: fund browser flows for advertised action limits

* Decouple payments into operator adapters and metered credits (#115)

* feat: decouple payments into operator-owned credit adapters

* feat: include generic payment method selection

* fix: require either a credit target or legacy payment amount

* docs: record payment extraction and live rollout verification

* fix(ci): restore core coverage after payment adapter extraction

* fix(test): isolate registry fixtures from optional payment implementation

* fix(ci): verify public browser flows without private payment adapters

* fix(ci): use deterministic preview origins and budget restored core proofs

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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