# Quick ops runbook — Economic Primitives (Futures · Judgment · Firm)

**Service:** `runtime/economic-primitives-server.mjs`  
**Surface:** Delx Commerce only · non-custodial  
**Local default port:** `8791` (`ECONOMIC_PRIMITIVES_PORT`)
**Installed private-beta port:** `8796` (loopback only)
**Current stage:** `private_beta`, loopback/private only

The complete operational contract, SLO targets, backup/restore design, incident
runbooks, and deployment gates are in
[`docs/economic/OPERATIONS_AND_SLOS.md`](../economic/OPERATIONS_AND_SLOS.md).
The release decision is
[`docs/economic/RELEASE_CHECKLIST.md`](../economic/RELEASE_CHECKLIST.md).

## Start the local/private candidate

```bash
cd 03-delx-platform/delx-agent-commerce
export ECONOMIC_PRIMITIVES_STATE_DIR="${ECONOMIC_PRIMITIVES_STATE_DIR:-$PWD/.delx-economic-state}"
export ECONOMIC_PRIMITIVES_PORT=8791
npm run economic:start
```

The following is a minimal process-supervision illustration only. It is not
installed, hardened, or deployment evidence:

```ini
[Service]
WorkingDirectory=/opt/delx-agent-commerce/current
Environment=ECONOMIC_PRIMITIVES_STATE_DIR=/var/lib/delx-agent-commerce/economic
Environment=ECONOMIC_PRIMITIVES_PORT=8791
ExecStart=/usr/bin/node runtime/economic-primitives-server.mjs
Restart=on-failure
```

Private beta additionally requires a dedicated service user, immutable release,
live managed keys, host metrics/alerts, encrypted off-site backup, and a real
restore drill. The local candidate already implements authenticated private
HTTP, Ed25519 receipts, one-writer persistence, bounded telemetry, graceful
drain, local encrypted backup/restore, and migration/quarantine tests.

## Installed private-beta service

The private production instance is intentionally separate from the compatibility
gateway. It is not routed through Caddy and is not a public mutation API.

| Item | Value |
| --- | --- |
| Unit | `delx-economic-primitives.service` |
| User/group | `delx-economic:delx-economic` |
| Release | `/opt/delx-agent-commerce/current` (immutable release symlink) |
| Listener | `127.0.0.1:8796` |
| State | `/var/lib/delx-economic-primitives/economic-primitives.json` |
| Config | `/etc/delx-economic-primitives/economic.env` (mode `0640`) |
| Receipt key | `/etc/delx-economic-primitives/receipt-key.pem` (mode `0640`) |
| Principal keys | `/etc/delx-economic-primitives/principal-public-keys.json` |
| Backup | `economic-primitives-state` in the shared encrypted off-site job |

Install/readback contract (run only with the service lease held):

```bash
serverctl audit --scope full
systemctl is-active delx-economic-primitives.service
curl --fail --silent http://127.0.0.1:8796/health
curl --fail --silent http://127.0.0.1:8796/ready
```

The unit keeps the service on loopback, uses a dedicated non-login account,
allows writes only to the state directory, and drains authenticated mutations
on `SIGTERM`. Any public route would be a separate approval and must use
`gatewayctl`; this unit has no public route by design.

## Health & readiness

| Path | Expect |
| --- | --- |
| `GET /health` | `status=ok`, product boundaries, `custody=false` |
| `GET /ready` | `status=ready` when the current snapshot flushes; `state_path` is internal |
| `GET /.well-known/delx-economic.json` | discovery document for all three products |

Important: a corrupt or unknown snapshot fails closed with `store_corrupt` or
`store_schema_unsupported`, quarantines unreadable JSON, returns not-ready, and
fences mutations. Restore still requires a verified backup and an explicit
operator decision; the runtime never silently invents an empty production state.

Body over 64 KiB returns 413. The local single-process limiter defaults to
120 mutations/minute and keys authenticated traffic by principal/tenant; it is
not sufficient behind an unverified public reverse proxy or across instances.

## Data location

- Default: `$PWD/.delx-economic-state/economic-primitives.json` (mode 0600, dir 0700)
- Override: `ECONOMIC_PRIMITIVES_STATE_DIR`
- Atomic write: `*.tmp` + fsync + rename + parent-directory fsync
- One writer only, enforced by an exclusive lock and monotonic revision
- Versioned v1↔v2 migration and unknown-version refusal
- Local encrypted backup/restore with source hash and revision receipt
- Off-site schedule, host alerts, and RPO/RTO remain deployment evidence

## Smoke

```bash
npm run economic:test
SCRATCH_OUT="$(mktemp -d)" npm run economic:smoke
```

`economic:smoke` boots durable mode with synthetic Ed25519 credentials and runs
one lifecycle per product. Always set `SCRATCH_OUT` during routine verification
so committed receipts are not overwritten; this is local evidence, not live
deployment evidence.

## Deployment boundary (Hetzner / shared host)

1. Audit and claim the exact `serverctl` service lease before any host change.
2. Do **not** edit Caddy by hand; use `gatewayctl` for every route change.
3. Register service, user, port, state, backup, probes, and rollback in the
   server manifest/runbook.
4. Keep the listener on loopback. Public exposure requires all public-beta
   gates and explicit owner approval.
5. Probe this service and all shared-host neighbors after the change.

Local green tests prove candidate behavior only. The installed private-beta
receipt is the source for live state; do not reuse it to claim public exposure,
custody, financial settlement, or GA.

## Boundary

Never route these as Protocol recovery. Never claim live USDC custody. Never mix Demand Board RFQ into Futures schemas.

Never call `majority|unanimous` enforced governance, `solver_paid` a payment,
Futures a transferable financial contract, or a Firm a legal entity under v1.

## Related

- Product hub: `/economic/`  
- Manifest: `/economic/manifest.json`  
- MVP doc: `docs/ECONOMIC_PRIMITIVES_MVP.md`  
- Normative docs: `docs/economic/README.md`
- API: `docs/economic/API_REFERENCE.md` · `docs/economic/openapi.json`
- Security: `docs/economic/SECURITY_AND_PRIVACY.md`
- Operations/SLOs: `docs/economic/OPERATIONS_AND_SLOS.md`
- Release: `docs/economic/RELEASE_CHECKLIST.md`
