Skip to main content

Fulfillment and seller delivery

Outcome. You understand exactly what happens on your side after a buyer settles: how fulfillment binds reserved capacity to a physical resource, executes provisioning, returns credentials, and recovers from failure — and which parts stay under your explicit control.

Delivery follows Settlement and stays seller-owned

Commercial agreement and physical delivery are deliberately separate. After escrow verification, the storefront coordinates fulfillment through seller infrastructure; no Registry or platform actor participates. For the VM domain the pinned lifecycle is:

Capacity Reservation
-> scheduler selects and binds one settlement resource
-> provider executes (create), may validate but never substitutes
-> provider result + provisioned resources (credentials, ports)
-> status / teardown / durable results

Scheduling and provider execution are separate authorities: the scheduler places; the provider executes against the placed resource. Retries for the same reservation return the existing assignment or result; conflicting retries are rejected. Evidence: fulfillment specification.

Mock first, then live

[provisioning].mode = "mock" validates the storefront ↔ chain ↔ Registry surface without touching libvirt — a buyer purchase returns simulated VM credentials. Live KVM provisioning adds the SSH key bind-mount, the baked Ansible inventory, and host prerequisites; the synchronized steps are in the seller quickstart.

Before trusting a live node, prove reachability from the provisioning container:

docker compose -f compose/seller.yml -f compose/seller.live.yml exec \
seller-provisioning ansible \
-i /opt/domains/vms/provisioning/iac/ansible/inventory/hosts \
<your_host_alias> -m ping

Expected output: SUCCESS with "ping": "pong" — the synchronized quickstart's own criterion that "the next buy will actually create a VM".

Lease end and release

Leases auto-expire at the agreed duration; the seller-side lease watchdog releases the resource and claims or refunds the escrow once the timeout passes. Physical release is proof-driven: capacity stays held until executor or provider teardown succeeds, and an operator may force release only after external verification — the audit state distinguishes forced release from proven teardown. Lease expiry is provisioning-owned and does not depend on a storefront callback.

The fulfillment failure policy

The storefront's failure policy is a commercial and administrative repair surface — not the physical release authority:

[fulfillment.failure_policy]
actions = ["emit_event", "webhook", "refund"]
webhook_url = "https://alerts.example/internal/arkhai/fulfillment-failed"

emit_event writes an observable stage event; webhook posts the failure payload; refund attempts the explicit seller refund path through the selected escrow codec. release_capacity exists as explicit admin repair for reservations proven safe outside the lifecycle — do not configure it as an automatic response to provider failure, because provisioning-owned teardown is authoritative. Synchronized detail: Configuration.

Troubleshoot

  • Authenticated site calls fail closedadmin_api_key is empty or missing; reservation, scheduling, result, and teardown calls all require it.
  • Grant or teardown never reaches the host — the inventory alias does not match, or the baked inventory predates your edit: rebuild with make build-seller.
  • Buyers reach the wrong address — set public_host= on the inventory line when tenants connect on a different address than the provisioner.

Next steps

Source and revision

The fulfillment and physical-provisioning contracts cited above are inspected at the exact SCM commit recorded in Source and revisions. They establish source behavior, not the availability of a hosted provisioning service.