@ixo/decision-oracle 0.2.21 → 0.2.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,7 +7,7 @@ for (a courier API says the parcel arrived, a model says the photo shows what it
7
7
  says this is not a duplicate), hands those facts to the IXO **decision engine**, and signs the
8
8
  verdict the engine returns on chain with your own key.
9
9
 
10
- This repository is the package that is all of that **except the facts**. You write a config object
10
+ This package is all of that **except the facts**. You write a config object
11
11
  and a handful of async functions; `@ixo/decision-oracle` brings the claim pulling, the engine handshake,
12
12
  the D1 ledgers, human-review folds, the chain write, billing pauses, email and Matrix notices, the
13
13
  cron and the Workflows. It is for developers who want to run an oracle as a service, for teams
@@ -16,9 +16,8 @@ publishing a protocol and its rubric, and for anyone who needs a claim judged th
16
16
  **The rubric is the work order. The engine decides. You produce facts and sign.**
17
17
 
18
18
  > **Learn more**
19
- > · Step-by-step guide: [`packages/eval-oracle/docs/guide.md`](https://github.com/ixoworld/eval-oralce/blob/main/packages/eval-oracle/docs/guide.md)
20
- > · Full API reference: [`packages/eval-oracle/docs/api.md`](https://github.com/ixoworld/eval-oralce/blob/main/packages/eval-oracle/docs/api.md)
21
- > · The engine's wire contract: [`docs/ENGINE-CONTRACT.md`](https://github.com/ixoworld/eval-oralce/blob/main/docs/ENGINE-CONTRACT.md)
19
+ > · Step-by-step guide: [docs.ixo.world — Decision oracle](https://docs.ixo.world/build-an-oracle/decision-oracle)
20
+ > · Full API reference: [docs.ixo.world — Decision oracle API reference](https://docs.ixo.world/build-an-oracle/decision-oracle/api-reference)
22
21
 
23
22
  ---
24
23
 
@@ -360,7 +359,7 @@ whole surface. `out.issues` is empty iff the engine would accept this FactSet. T
360
359
  Pass `stock` in `fakeTools({ … })` (or `runFacts`'s `stock` option) when the handler under test
361
360
  wraps it.
362
361
 
363
- Full reference: [`packages/eval-oracle/docs/api.md`](https://github.com/ixoworld/eval-oralce/blob/main/packages/eval-oracle/docs/api.md).
362
+ Full reference: [Decision oracle API reference](https://docs.ixo.world/build-an-oracle/decision-oracle/api-reference).
364
363
 
365
364
  ## CLI reference
366
365
 
@@ -467,7 +466,7 @@ under `--json` that dry run prints nothing on stdout.
467
466
  Agents reach the same lane through the hosted MCP server at `https://<oracle>/v1/mcp` —
468
467
  `claude mcp add --transport http ixo https://<oracle>/v1/mcp --header "Authorization: Bearer eo_live_…"`
469
468
  (plus `X-Payment-Delegation` for an `x402` source): `submit_claim`, `get_decision`, `list_protocols`,
470
- `verify_receipt`, under the key's own scopes and limits (`docs/api.md`, "Use with Claude Code and
469
+ `verify_receipt`, under the key's own scopes and limits ([API reference](https://docs.ixo.world/build-an-oracle/decision-oracle/api-reference), "Use with Claude Code and
471
470
  other MCP clients").
472
471
 
473
472
  ### Protocol authoring (the commissioner's side)
@@ -493,7 +492,7 @@ Two places, and the split is the rule: **public config in `wrangler.jsonc` `vars
493
492
  | Var | What it is |
494
493
  | --- | --- |
495
494
  | `IXO_NETWORK` | `devnet` / `testnet` / `mainnet` — supplies every per-network URL below |
496
- | `ORACLE_HOSTNAME` | the host this oracle's `did:web` is served from; **must equal the Custom Domain in `routes`** |
495
+ | `ORACLE_HOSTNAME` | the host this oracle's `did:web` is served from: your Custom Domain in `routes`, or, with no custom domain, the Worker's free `<worker>.<account>.workers.dev` host |
497
496
  | `ORACLE_ADDRESS`, `ORACLE_DID` | the public chain identity (asserted against `ORACLE_SECP_MNEMONIC` at first use — a mismatch fails loud) |
498
497
  | `ORACLE_MATRIX_USER_ID` | the oracle bot's MXID, `@did-ixo-<address>:<homeserver>` |
499
498
  | `ORACLE_ENTITY_DID` | the on-chain oracle ENTITY from `oracle init` — **required for a deployed oracle**: unset on a non-local `ORACLE_HOSTNAME`, `/health/ready` fails its `identity` check (local dev is exempt). Unset, the Matrix review card also falls back to `ORACLE_DID` and reviews work only from the portal page |
@@ -598,7 +597,7 @@ The bindings the template declares: **D1** (`DB` — the ledgers), **KV** (`CACH
598
597
  two **Workflows** (`CLAIM_WORKFLOW`, `REVIEW_WORKFLOW`), a **Durable Object** (`SEQUENCE_MANAGER`,
599
598
  the chain sequence keeper), two **rate limiters** (`API_RATE_LIMITER` per IP, `API_KEY_RATE_LIMITER`
600
599
  per API key for the Decision API lane), **email** (`EMAIL`), and three **cron** triggers (every minute, every five minutes, hourly — keep all three) — plus an
601
- optional **R2** bucket (`API_UPLOADS`, commented out: absent ⇒ the upload route answers 501), and an optional answer archive (`ANSWERS_ARCHIVE`, commented out: bound ⇒ every evaluated ask, answer and photo is kept in that private bucket, one `<askId>-<title>/` folder per ask, shaped by `defineOracle`'s `archive` hooks — [guide §12](https://github.com/ixoworld/eval-oralce/blob/main/packages/eval-oracle/docs/guide.md#12-operating-it)). Every binding and the whole `vars` block are redeclared per env — they inherit
600
+ optional **R2** bucket (`API_UPLOADS`, commented out: absent ⇒ the upload route answers 501), and an optional answer archive (`ANSWERS_ARCHIVE`, commented out: bound ⇒ every evaluated ask, answer and photo is kept in that private bucket, one `<askId>-<title>/` folder per ask, shaped by `defineOracle`'s `archive` hooks — [guide, "Operating it"](https://docs.ixo.world/build-an-oracle/decision-oracle#12-operating-it)). Every binding and the whole `vars` block are redeclared per env — they inherit
602
601
  nothing from the top level.
603
602
 
604
603
  `db:migrate:remote` applies the migrations that ship **inside the package** (`migrations_dir`
@@ -607,9 +606,13 @@ per-environment step: for a named env, run `wrangler d1 migrations apply <name>-
607
606
  --env testnet`, likewise `--env production`. A Worker deployed against an unmigrated D1 fails on
608
607
  its first claim.
609
608
 
610
- **The Custom Domain in `routes` must equal `ORACLE_HOSTNAME`** for the env you deploy: callers
611
- verify you by fetching `https://<ORACLE_HOSTNAME>/.well-known/did.json`, and the engine binds its
612
- records to that did:web.
609
+ **`ORACLE_HOSTNAME` must be the host the env is served from**: callers verify you by fetching
610
+ `https://<ORACLE_HOSTNAME>/.well-known/did.json`, and the engine binds its records to that did:web.
611
+ A custom domain is optional. Without one, delete that env's `routes` entry and set
612
+ `ORACLE_HOSTNAME` to the Worker's free `<worker name>.<your account subdomain>.workers.dev` host
613
+ (wrangler prints it on deploy; with no `routes`, wrangler serves `workers.dev` by default). With
614
+ one, the Custom Domain in `routes` must equal `ORACLE_HOSTNAME`. Pick the host before `oracle
615
+ init`: it IS the oracle's identity, so moving to a custom domain later means a new did:web.
613
616
 
614
617
  ### Declaring yourself on chain
615
618
 
@@ -726,9 +729,6 @@ the exception** — the hosted subscriptions API resolves the ENGINE's did:web t
726
729
  delegation, so that leg needs a public tunnel in front of the engine, with the tunnel host set as
727
730
  the engine's hostname everywhere and the CAR minted for that same audience.
728
731
 
729
- The full runbook, plus the two engine-conformance harnesses:
730
- [`packages/eval-oracle/dev/README.md`](https://github.com/ixoworld/eval-oralce/blob/main/packages/eval-oracle/dev/README.md).
731
-
732
732
  ## Repository layout
733
733
 
734
734
  ```text
@@ -784,6 +784,6 @@ symlinks are not packed). CI diffs them — change one, copy it to the other.
784
784
 
785
785
  ## Status
786
786
 
787
- Published on npm: `@ixo/decision-oracle` 0.2.21 and `@ixo/decision-oracle-client` 0.1.1.
787
+ Published on npm: `@ixo/decision-oracle` 0.2.22 and `@ixo/decision-oracle-client` 0.1.1.
788
788
 
789
789
  Apache License 2.0: `LICENSE` at the repo root and in each package.
package/docs/api.md CHANGED
@@ -1629,7 +1629,7 @@ once deployed. Every value is validated by Zod at isolate start, so a bad env fa
1629
1629
  | `EVAL_ENGINE_HOSTNAME` | vars | per network | The engine you ask for decisions. A host you **call** — its `did:web` is the invocation audience. Set it for a local engine or a tunnel |
1630
1630
  | `CLAIM_BOT_URL_OVERRIDE` | `.dev.vars` | derived | Local harnesses only — the bot URL is normally derived as `https://claim.bot.<homeserver domain>` |
1631
1631
  | `IXO_CLIENT_SEQUENCE_MIN_DELAY_MS` | vars | `1000` | Read by the sequence keeper off `env`: the minimum gap between two sequence allocations |
1632
- | `ORACLE_HOSTNAME` | vars | **required** | *Your* canonical `did:web` host. Every inbound invocation's audience is pinned to this, never the request `Host`; it is also the issuer of every invocation you mint. It must equal the Custom Domain in `routes` for that env |
1632
+ | `ORACLE_HOSTNAME` | vars | **required** | *Your* canonical `did:web` host. Every inbound invocation's audience is pinned to this, never the request `Host`; it is also the issuer of every invocation you mint. It must equal the Custom Domain in `routes` for that env, or, with no `routes`, the env's `<worker>.<account>.workers.dev` host |
1633
1633
  | `ORACLE_DID` | vars | **required** | `did:ixo:<address>` — the runtime chain identity |
1634
1634
  | `ORACLE_ADDRESS` | vars | **required** | Must be the `ORACLE_SECP_MNEMONIC` wallet's address — asserted at first use, fails loud |
1635
1635
  | `ORACLE_MATRIX_USER_ID` | vars | **required** | The MXID derived from `ORACLE_DID` (cross-checked, never re-derived) |
package/docs/guide.md CHANGED
@@ -103,9 +103,12 @@ asserted against the mnemonic before the first signature: a hand-typed one that
103
103
  never signs as someone else.
104
104
 
105
105
  Also set, in `wrangler.jsonc` `vars`: `IXO_NETWORK`, and `ORACLE_HOSTNAME` — the host your
106
- `did:web` is served from (`localhost:8787` while developing). **It must equal the Custom Domain in
107
- `routes` for any environment you deploy**, because callers resolve you by fetching
108
- `https://<host>/.well-known/did.json`. And in `.dev.vars`: `UNIQUE_HMAC_KEY`, any long random
106
+ `did:web` is served from (`localhost:8787` while developing). **It must be the host each
107
+ environment you deploy is served from**, because callers resolve you by fetching
108
+ `https://<host>/.well-known/did.json`. A custom domain is optional: delete that env's `routes`
109
+ entry and the Worker is served on its free `<worker name>.<account subdomain>.workers.dev` host —
110
+ set `ORACLE_HOSTNAME` to that. With a custom domain, it must equal the Custom Domain in `routes`.
111
+ Pick the host before `oracle init` (§10): it is the oracle's identity. And in `.dev.vars`: `UNIQUE_HMAC_KEY`, any long random
109
112
  string, if the rubric you serve declares a `unique` rule.
110
113
 
111
114
  Both of these keys are, at this point, only strings in your files. `decision-oracle oracle init` (§10)
@@ -983,8 +986,9 @@ Before shipping an environment, check all four:
983
986
 
984
987
  1. the **D1 and KV ids** in that env's block are real (named envs inherit nothing — every binding
985
988
  and the whole `vars` block is redeclared per env);
986
- 2. the **Custom Domain** in `routes` equals that env's `ORACLE_HOSTNAME`, character for character —
987
- callers resolve your `did:web` by fetching it;
989
+ 2. that env's `ORACLE_HOSTNAME` is, character for character, the host it is served from — the
990
+ **Custom Domain** in `routes`, or, with no `routes`, its `workers.dev` host — callers resolve
991
+ your `did:web` by fetching it;
988
992
  3. every **secret** is set with `wrangler secret put` for that env — including
989
993
  `ORACLE_MATRIX_ACCESS_TOKEN`, the one `oracle init` wrote into your local `.dev.vars`
990
994
  (`wrangler secret put ORACLE_MATRIX_ACCESS_TOKEN`, then paste it);
@@ -1529,7 +1533,7 @@ own retries, and a terminal failure clears it.
1529
1533
 
1530
1534
  | Symptom | Cause | Fix |
1531
1535
  | --- | --- | --- |
1532
- | `401` on any `/v1` call | The invocation's audience is not `did:web:<ORACLE_HOSTNAME>`, or `/.well-known/did.json` is not served from that host | Make `ORACLE_HOSTNAME`, the Custom Domain and the audience the same string. Check `SERVICE_ED25519_MNEMONIC` is set |
1536
+ | `401` on any `/v1` call | The invocation's audience is not `did:web:<ORACLE_HOSTNAME>`, or `/.well-known/did.json` is not served from that host | Make `ORACLE_HOSTNAME`, the served host (Custom Domain or `workers.dev`) and the audience the same string. Check `SERVICE_ED25519_MNEMONIC` is set |
1533
1537
  | `401` from the claim bot, the UCAN Store or the VFS claims lane (`claim.store-denied`), on an invocation minted as `did:ixo:…` | That DID has no IID document, or the `SERVICE_ED25519_MNEMONIC` key is not a verification method on it — the resolver has nothing to check the signature against | Re-run `oracle init --protocol <protocol did> --kit-url https://<your host> --yes`: every step already done says `skip`, so only the missing `iid` / `key` writes anything. (`--protocol` and `--kit-url` are always required, and `--only <step>` without `--yes` is still just a dry run) |
1534
1538
  | `bunx @ixo/decision-oracle@<version>` says `No version matching … found (but package exists)` right after a release | bun's cached copy of the package list is older than the release | `bun pm cache rm`, then run it again — or `BUN_INSTALL_CACHE_DIR=$(mktemp -d) bunx @ixo/decision-oracle@<version> …` |
1535
1539
  | A protocol shows as "Unnamed" in the portal, the console or the Openhands app | It has no `#pro` profile: `publish-protocol` writes one only with `--name` | `publish-protocol --phase profile --entity <protocol did> --rubric <file> --form <file> --name "<name>" [--description "<text>"] --yes` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ixo/decision-oracle",
3
- "version": "0.2.21",
3
+ "version": "0.2.22",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Run an IXO evaluation oracle: pull claims, produce facts with your handlers, let the decision engine decide, sign on chain",
6
6
  "keywords": [
@@ -12,14 +12,7 @@
12
12
  "hono",
13
13
  "d1"
14
14
  ],
15
- "repository": {
16
- "type": "git",
17
- "url": "git+https://github.com/ixoworld/eval-oralce.git"
18
- },
19
- "bugs": {
20
- "url": "https://github.com/ixoworld/eval-oralce/issues"
21
- },
22
- "homepage": "https://github.com/ixoworld/eval-oralce#readme",
15
+ "homepage": "https://docs.ixo.world/build-an-oracle/decision-oracle",
23
16
  "type": "module",
24
17
  "exports": {
25
18
  ".": {
@@ -97,8 +97,14 @@ it in an agent session, or the mnemonic lands in the transcript.
97
97
  `wrangler.jsonc` `vars` (top level and every env), not `.dev.vars`.
98
98
 
99
99
  `ORACLE_HOSTNAME` (the host the did:web is served from) is `localhost:8787` in `.dev.vars` for local
100
- dev ONLY. Each deployed env's host lives in that env's `wrangler.jsonc` `vars` and must equal its
101
- Custom Domain in `routes`; a per-env secrets file (`.dev.vars.<env>`) must NOT carry a localhost
100
+ dev ONLY. Each deployed env's host lives in that env's `wrangler.jsonc` `vars` and must be the
101
+ host that env is served from. **A custom domain is optional**: without one, delete that env's
102
+ `routes` entry (with no `routes`, wrangler serves the Worker on `workers.dev`; `"workers_dev": true`
103
+ says so explicitly) and set `ORACLE_HOSTNAME` to the free `<worker name>.<account subdomain>.workers.dev`
104
+ host — the env's `name` (e.g. `<project>-devnet`) plus the account's workers.dev subdomain
105
+ (dashboard → Workers & Pages; the first deploy prints the URL). With a custom domain,
106
+ `ORACLE_HOSTNAME` must equal the Custom Domain in `routes`. Choose before `oracle init`: the host IS
107
+ the did:web, so changing it later is a new identity. A per-env secrets file (`.dev.vars.<env>`) must NOT carry a localhost
102
108
  `ORACLE_HOSTNAME`, or `engine register --env-file .dev.vars.<env>` registers localhost. Also put
103
109
  `UNIQUE_HMAC_KEY` in `.dev.vars` (any long random string; rotating it orphans every registered
104
110
  duplicate digest). `derive "<existing mnemonic>"` uses a wallet the provider already holds instead of
@@ -322,8 +328,9 @@ bun run deploy:devnet # or deploy:testnet / deploy:production (`--env
322
328
  wrangler secret put ORACLE_MATRIX_ACCESS_TOKEN # the value step 8 wrote into .dev.vars
323
329
  ```
324
330
 
325
- Before deploying: the D1/KV ids for that env are real, the Custom Domain equals that env's
326
- `ORACLE_HOSTNAME`, and every secret is set with `wrangler secret put`. **Then run step 8 again with
331
+ Before deploying: the D1/KV ids for that env are real, that env's `ORACLE_HOSTNAME` is the host
332
+ it will be served from (its Custom Domain in `routes`, or, with no `routes`, its `workers.dev`
333
+ host), and every secret is set with `wrangler secret put`. **Then run step 8 again with
327
334
  `--kit-url https://<the deployed host>` and `--yes`**: the `service` step re-points `#eval` at the
328
335
  real host and `profile` anchors the `#pro` it had to skip. `fund` may act again too — it is a floor
329
336
  check, so a wallet the first run's own `iid`/`key` transactions left below 1 IXO is topped back
@@ -389,7 +396,7 @@ the required fee (`pricing.byProtocol` for that collection's protocol, else the
389
396
  | Identity | a fresh wallet, or an existing mnemonic to derive from | `derive`, `.dev.vars` + `wrangler.jsonc` vars |
390
397
  | Owner | who owns this oracle — the AuthHub login whose subscription pays the engine | `login`, `delegation --for engine` |
391
398
  | Funding | nothing to ask — `oracle init` keeps the wallet topped up to 1 IXO for gas | `oracle init` (the `fund` step) |
392
- | Hosts | the did:web host per env (it IS the identity) | `ORACLE_HOSTNAME`, `routes` |
399
+ | Hosts | the did:web host per env (it IS the identity): a custom domain, or the free `workers.dev` host | `ORACLE_HOSTNAME`, `routes` (none for `workers.dev`) |
393
400
  | Contact | the address that gets pause / review notices | `register --contact-email` |
394
401
 
395
402
  ## Safety rules
@@ -417,7 +424,7 @@ the required fee (`pricing.byProtocol` for that collection's protocol, else the
417
424
  | Guessing `EVALUATION_MIN_AMOUNT` | ask what the collection's on-chain evaluation payment is (or will be) — set too high and register 402s |
418
425
  | No `EVALUATION_DENOM` in the mainnet env | the worker refuses to start — set both vars in every env you deploy |
419
426
  | `allowAiChecks: false` while the work order declares AI checks | every `ai` fact freezes `error` and the rubric's `onError` decides — ask first |
420
- | `ORACLE_HOSTNAME` ≠ the deployed Custom Domain | callers resolve the did:web by fetching that host — they must be the same string |
427
+ | `ORACLE_HOSTNAME` ≠ the host the env is served from (its Custom Domain, or its `workers.dev` host) | callers resolve the did:web by fetching that host — they must be the same string |
421
428
  | `ORACLE_ENTITY_DID` left unset after `oracle init` (or set only at the top level) | the deployed oracle fails `/health/ready` (`identity`); the Matrix review card can't resolve it, so reviews only work from the portal page |
422
429
  | Running `oracle init --yes` with nothing serving `--kit-url` | `profile`, `domain` and `acard` skip (all three are built from the live `GET /v1/info`) — start `bun run dev`, or deploy, before the run that should anchor them |
423
430
  | Skipping `--logo` without asking | the identity is still complete, but the portal, the console and the Openhands app show a placeholder — ask the provider for a logo (URL or image file) and pass `--logo` |
@@ -46,7 +46,7 @@ is the package CLI.
46
46
  ### 0. Prerequisites
47
47
 
48
48
  ```bash
49
- bunx wrangler whoami # the Cloudflare account that owns your host's zone
49
+ bunx wrangler whoami # the Cloudflare account the oracle deploys to
50
50
  bunx decision-oracle login --network devnet # the OWNER's AuthHub session — once
51
51
  ```
52
52
 
@@ -55,7 +55,7 @@ bunx decision-oracle login --network devnet # the OWNER's AuthHub session
55
55
  Put the session's OWN DID (`did:ixo:<address>` — `login` prints the address) in
56
56
  `ORACLE_ADMIN_DIDS` in every `vars` block of `wrangler.jsonc`. The example ships IXO's DID there —
57
57
  a copy of it must replace it with the owner's.
58
- - The account must hold the zone of the host, or the Custom Domain cannot attach. If `whoami` shows another account, stop and say so (**HUMAN**).
58
+ - A custom domain is optional. Without one, delete each env's `routes` entry and set that env's `ORACLE_HOSTNAME` to the Worker's free `<worker name>.<account subdomain>.workers.dev` host (the first deploy prints it). With one, the account must hold the zone of the host, or the Custom Domain cannot attach — if `whoami` shows another account, stop and say so (**HUMAN**). Either way the host IS the did:web: pick it before `oracle init`.
59
59
 
60
60
  ### 1. The protocol (example: publish `protocol/`; a provider: their protocol's DID)
61
61
 
@@ -313,13 +313,13 @@ Decision Console shows the price and card eligibility read-only.
313
313
 
314
314
  | Symptom | Cause → fix |
315
315
  | --- | --- |
316
- | Console / CLI 401 `UNAUTHORIZED` on a UCAN call | audience mismatch: the invocation names the did:web read from `<host>/.well-known/did.json` — `ORACLE_HOSTNAME` must equal the Custom Domain, and `--kit` must be that host |
316
+ | Console / CLI 401 `UNAUTHORIZED` on a UCAN call | audience mismatch: the invocation names the did:web read from `<host>/.well-known/did.json` — `ORACLE_HOSTNAME` must equal the host the env is served from (its Custom Domain, or its `workers.dev` host), and `--kit` must be that host |
317
317
  | Worker 500s on every request after deploy; logs say `WEBHOOK_ENCRYPTION_KEY: required when API_LANE is on` | the secret is missing in that env — `bunx wrangler secret put WEBHOOK_ENCRYPTION_KEY --env <env>` (for a new deployment only; never replace an existing one) |
318
318
  | `PROTOCOL_NOT_ALLOWED` on submit | the source's allow-list lacks it — empty means NONE; `api admin protocols <src> <did> --yes` |
319
319
  | 503 `SOURCE_PAUSED` `payments-disabled` | `API_PAYMENTS` is off and the source bills `x402` — turn payments on, or `api admin billing-mode <src> none` |
320
320
  | 402 again after a `PAYMENT-SIGNATURE` | the facilitator refused the payer: no deed / no `SendAuthorization` / not enough PAY — the fresh 402's error says which |
321
321
  | offers refused `plan_inactive`, `accepts: []` | the facilitator finds no active plan for the oracle: it is not registered with the engine (step 6 — registered, it runs on Standard at once), or, for an IXO-run oracle, IXO has not activated its plan (**HUMAN**: ask IXO). A way to pay whose payee is unset (`EARNINGS_ADDRESS` for PAY / USDC on IXO, `EARNINGS_BASE_WALLET` for USDC on Base) is simply not offered |
322
- | Not listed in the console | not registered with the engine (step 6), or not payable (the row above); or the host is not a `*.ixo.earth` Custom Domain; or `CORS_ORIGINS` lacks `https://decision-console.devnet.ixo.earth` |
322
+ | Not listed in the console | not registered with the engine (step 6), or not payable (the row above); or `https://<ORACLE_HOSTNAME>/.well-known/did.json` does not answer; or `CORS_ORIGINS` lacks `https://decision-console.devnet.ixo.earth` |
323
323
  | Every API claim rejects with `frequency` | the caller sends no `submitter` — an uncountable window fails closed; send the courier id |
324
324
  | 409 `REVIEW_EXPIRED` on a review answer | the paid claim's `answerBy` (its x402 reservation's expiry: extended up to 30 days for the review, else 24 h after verify) has passed — it can no longer be paid, and nothing was written. Answer paid reviews before the date the emails state |
325
325
  | Claims go `pending_review` on `SD-RT-CHECKS` (example) | an errored fact (onError `review`) held them for a person: the AI provider unavailable (the photo check — no gateway credits, or `OPENROUTER_API_KEY` missing on `openrouter`), or the orders endpoint unreachable (`DEMO_ORDERS` off, or an `ORD-…-E` order) — read the claim's report; fix it, and new claims decide again (the held ones are answered in the console). A rubric without a claim-level ReviewTask parks such claims `review` with NO task — give it one |
@@ -143,8 +143,10 @@ under `/v1` requires a UCAN invocation addressed to `did:web:<ORACLE_HOSTNAME>`.
143
143
  bun run deploy:devnet # or deploy:testnet / deploy:production
144
144
  ```
145
145
 
146
- The Custom Domain in `routes` must equal `ORACLE_HOSTNAME` — the did:web document is served from
147
- it, and that is how anyone verifies who you are.
146
+ `ORACLE_HOSTNAME` must be the host the env is served from — the did:web document is served from
147
+ it, and that is how anyone verifies who you are. A custom domain is optional: with no `routes`
148
+ entry, the Worker is served on its free `<worker name>.<account subdomain>.workers.dev` host, and
149
+ `ORACLE_HOSTNAME` is that host. With one, it must equal the Custom Domain in `routes`.
148
150
 
149
151
  `GET /v1/info` only answers a portal that already knows your host. For discovery that starts from
150
152
  the protocol, declare yourself on chain — an oracle entity, a `#eval` service pointing at your
@@ -5,7 +5,9 @@
5
5
  "compatibility_date": "2026-07-07",
6
6
  "compatibility_flags": ["nodejs_compat"],
7
7
 
8
- // The Custom Domain IS the did:web identity — it must equal ORACLE_HOSTNAME below.
8
+ // The host IS the did:web identity — ORACLE_HOSTNAME below must be the host the Worker is served
9
+ // from. A custom domain is optional: with no `routes`, the Worker is served on its free
10
+ // `<name>.<account subdomain>.workers.dev` host — set ORACLE_HOSTNAME to that.
9
11
  // "routes": [{ "pattern": "<your ORACLE_HOSTNAME>", "custom_domain": true }],
10
12
 
11
13
  // D1 is the oracle's database: the ledger tables the package owns. `migrations_dir` points INTO
@@ -156,7 +158,8 @@
156
158
 
157
159
  // THIS oracle's did:web host — the audience every inbound UCAN invocation must name, and the
158
160
  // issuer of every invocation this oracle mints. It must equal the Custom Domain in `routes`
159
- // for the env you deploy: callers resolve you by fetching https://<host>/.well-known/did.json.
161
+ // (or, with no `routes`, the env's `workers.dev` host) for the env you deploy: callers resolve
162
+ // you by fetching https://<host>/.well-known/did.json.
160
163
  "ORACLE_HOSTNAME": "<REPLACE: the host your did:web is served from>",
161
164
 
162
165
  // This oracle's PUBLIC chain identifiers, printed together by `bunx decision-oracle derive`.
@@ -231,7 +234,8 @@
231
234
  // keeps the deployed name explicit and independent of the top-level one.
232
235
  "name": "{{name}}-devnet",
233
236
  // The Custom Domain IS the identity: it must equal ORACLE_HOSTNAME below. Declared here so
234
- // the deploy attaches it (and its DNS record) instead of it being a dashboard step.
237
+ // the deploy attaches it (and its DNS record) instead of it being a dashboard step. Optional:
238
+ // delete `routes` to serve on the free workers.dev host, and set ORACLE_HOSTNAME to that.
235
239
  "routes": [{ "pattern": "<REPLACE: your devnet host>", "custom_domain": true }],
236
240
  "vars": {
237
241
  "ENVIRONMENT": "staging",
@@ -340,7 +344,8 @@
340
344
  // keeps the deployed name explicit and independent of the top-level one.
341
345
  "name": "{{name}}-testnet",
342
346
  // The Custom Domain IS the identity: it must equal ORACLE_HOSTNAME below. Declared here so
343
- // the deploy attaches it (and its DNS record) instead of it being a dashboard step.
347
+ // the deploy attaches it (and its DNS record) instead of it being a dashboard step. Optional:
348
+ // delete `routes` to serve on the free workers.dev host, and set ORACLE_HOSTNAME to that.
344
349
  "routes": [{ "pattern": "<REPLACE: your testnet host>", "custom_domain": true }],
345
350
  "vars": {
346
351
  "ENVIRONMENT": "staging",