@ixo/decision-oracle 0.2.1 → 0.2.3
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 +8 -20
- package/dist/cli/commands/create-collection.d.ts.map +1 -1
- package/dist/cli/commands/create-collection.js +6 -3
- package/dist/cli/commands/create-collection.js.map +1 -1
- package/dist/lib/email/template.js +1 -1
- package/dist/lib/email/template.js.map +1 -1
- package/dist/lib/payments/gate.js +2 -2
- package/dist/lib/payments/gate.js.map +1 -1
- package/dist/lib/payments/review-billing.js +1 -1
- package/dist/lib/payments/review-billing.js.map +1 -1
- package/dist/lib/register.js +1 -1
- package/dist/lib/register.js.map +1 -1
- package/dist/routes/v1/api/openapi.gen.d.ts.map +1 -1
- package/dist/routes/v1/api/openapi.gen.js +1 -1
- package/dist/routes/v1/api/openapi.gen.js.map +1 -1
- package/docs/api.md +2 -2
- package/docs/guide.md +1 -1
- package/openapi/decision-api.yaml +8 -8
- package/package.json +1 -1
- package/skills/README.md +2 -0
- package/skills/add-openhands-support/SKILL.md +18 -17
- package/skills/create-collection/SKILL.md +17 -4
- package/skills/create-collection/reference/collection.md +2 -1
- package/skills/create-oracle/SKILL.md +61 -16
- package/skills/create-rubric/SKILL.md +3 -2
- package/skills/create-rubric/reference/format-cheatsheet.md +1 -1
- package/skills/decision-api-client/SKILL.md +42 -88
- package/skills/decision-api-oracle/SKILL.md +35 -33
- package/skills/publish-protocol/SKILL.md +18 -3
- package/skills/publish-protocol/reference/publishing.md +1 -1
- package/skills/reference/engine-contract.md +1 -1
- package/skills/reference/linked-docs.md +35 -0
- package/skills/write-facts/reference/facts-api.md +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openapi.gen.js","sourceRoot":"","sources":["../../../../src/routes/v1/api/openapi.gen.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,iGAAiG;AACjG,sEAAsE;AAEtE,mGAAmG;AACnG,wEAAwE;AACxE,MAAM,CAAC,MAAM,gBAAgB,GAA4B,IAAI,CAAC,KAAK,CAAC
|
|
1
|
+
{"version":3,"file":"openapi.gen.js","sourceRoot":"","sources":["../../../../src/routes/v1/api/openapi.gen.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,iGAAiG;AACjG,sEAAsE;AAEtE,mGAAmG;AACnG,wEAAwE;AACxE,MAAM,CAAC,MAAM,gBAAgB,GAA4B,IAAI,CAAC,KAAK,CAAC,+gkXAA+gkX,CAAC,CAAC"}
|
package/docs/api.md
CHANGED
|
@@ -1582,7 +1582,7 @@ once deployed. Every value is validated by Zod at isolate start, so a bad env fa
|
|
|
1582
1582
|
| `EARNINGS_ADDRESS` | vars | unset | Where your earnings for decisions land in PAY and USDC on IXO: your own `ixo1…` account, sent as each offer's `payTo` (the facilitator checks it, never picks one). Checked at start, checksum included. Needed only when IXO's plan for the oracle takes PAY (the engine's `GET /v1/oracles/me` `accepts` holds `upay`; KV-cached 5 min): unset then ⇒ new x402 submits answer `503 SOURCE_PAUSED { reason: payments-disabled }`. A plan without PAY (card and/or USDC on Base) sends no ixo-pay terms and never reads it; a plan the engine cannot tell is the same 503 |
|
|
1583
1583
|
| `EARNINGS_BASE_WALLET` | vars | unset | Your Base wallet (`0x…`) for USDC on Base. Unset ⇒ that way to pay is not offered |
|
|
1584
1584
|
| `BILLING_ENGINE_URL` | vars | unset | Charge lookups and the spend figures on `/v1/api/me`. No trailing slash |
|
|
1585
|
-
| `CONSOLE_URL` | vars | unset | The Decision Console — every error's `docsUrl`, the 402's `fundingUrl`, and every email link (the `balance.low` email's is `<CONSOLE_URL>/credits`). Unset ⇒ the API lane's emails are logged skips. No trailing slash |
|
|
1585
|
+
| `CONSOLE_URL` | vars | unset | The Decision Console — every error's `docsUrl`, the 402's `fundingUrl`, and every email link (the `balance.low` email's is `<CONSOLE_URL>/billing/credits`). Unset ⇒ the API lane's emails are logged skips. No trailing slash |
|
|
1586
1586
|
| `AUTH_HUB_URL` | vars | per `IXO_NETWORK` (`https://dev.auth.ixo.earth`, `https://test.auth.ixo.earth`, `https://auth.ixo.earth`) | IXO AuthHub, the OAuth server of `/v1/mcp`: the protected-resource metadata's `authorization_servers`, the exact `iss` of an access token (its JWKS at `<url>/.well-known/jwks.json`), the approve link's host, and the one `did:web` (`did:web:<its host>`) the approvals back-channel accepts. Set it only for a local AuthHub. No trailing slash |
|
|
1587
1587
|
| `ORACLE_ADMIN_DIDS` | vars | unset | Comma-separated `did:ixo` admins of this oracle — the oracle's operator's own people — allowed on `GET /v1/admin/status` and `/v1/api/admin/*`. Unset ⇒ nobody |
|
|
1588
1588
|
| `STATUS_READER_DIDS` | vars | unset | Comma-separated DIDs of any method (`did:web:…`, `did:ixo:…`, each checked as `did:<method>:<id>`) allowed to read `GET /v1/admin/status` and nothing else — for a monitoring service, e.g. your decision engine's status board, identified by its DID. Kept apart from `ORACLE_ADMIN_DIDS` so a monitor is never made an operator. Unset ⇒ nobody |
|
|
@@ -2069,7 +2069,7 @@ receivers de-duplicate on `Oracle-Event-Id`. An erased row stays erased and goes
|
|
|
2069
2069
|
minutes) reads each active source's payer balance against its `refillFloorCents`. The first read
|
|
2070
2070
|
below the floor sends one `balance.low` webhook (`{ sourceId, balanceCents, floorCents }`) and one
|
|
2071
2071
|
email to the source's `contactEmail`: the source's name, the balance and the floor as dollars, and
|
|
2072
|
-
an "Add credits" link to `${CONSOLE_URL}/credits`. The webhook goes once per crossing (a recovery
|
|
2072
|
+
an "Add credits" link to `${CONSOLE_URL}/billing/credits`. The webhook goes once per crossing (a recovery
|
|
2073
2073
|
above the floor re-arms it). The email goes once per UTC day while the balance stays under the
|
|
2074
2074
|
floor (`notice_balance_low:<sourceId>:<yyyy-mm-dd>`): still low tomorrow is a new email, a balance
|
|
2075
2075
|
bobbing around its floor within a day is one, and a send that fails is retried on the next check.
|
package/docs/guide.md
CHANGED
|
@@ -1280,7 +1280,7 @@ claim is ever blocked on one.
|
|
|
1280
1280
|
facilitator configured, the balance watch (every 5 minutes) sends a `balance.low` webhook the
|
|
1281
1281
|
first time the payer's balance drops below it, and emails the source's `contactEmail` once per UTC
|
|
1282
1282
|
day while it stays below (a send that fails is retried on the next check): the balance against the floor in dollars, and an "Add credits" link to your console's
|
|
1283
|
-
Credits page (`CONSOLE_URL/credits`). Without `CONSOLE_URL` or a sender, the email is a logged skip.
|
|
1283
|
+
Credits page (`CONSOLE_URL/billing/credits`). Without `CONSOLE_URL` or a sender, the email is a logged skip.
|
|
1284
1284
|
|
|
1285
1285
|
**Uptime and status.** Point your uptime monitor (Sentry Uptime, or any HTTP checker, every
|
|
1286
1286
|
minute) at `GET /health/ready`, not `/health`: `/health` only proves the worker boots, while
|
|
@@ -335,10 +335,10 @@ info:
|
|
|
335
335
|
|
|
336
336
|
|
|
337
337
|
**Changes in 1.19.0.** No wire change. The CLI gains the console's onboarding steps:
|
|
338
|
-
`decision-oracle org create` (an organisation entity, idempotent by name), `decision-oracle api
|
|
339
|
-
link <sourceId>` (signs the organisation's link, PUTs it to the engine and calls `POST
|
|
340
|
-
/v1/api/sources/{sourceId}/company/sync`: `pending-link` → `active`), `decision-oracle org
|
|
341
|
-
and `decision-oracle logout`.
|
|
338
|
+
`decision-oracle org create` (an organisation entity, idempotent by name), `decision-oracle api
|
|
339
|
+
source link <sourceId>` (signs the organisation's link, PUTs it to the engine and calls `POST
|
|
340
|
+
/v1/api/sources/{sourceId}/company/sync`: `pending-link` → `active`), `decision-oracle org
|
|
341
|
+
balance` and `decision-oracle logout`.
|
|
342
342
|
|
|
343
343
|
|
|
344
344
|
**Changes in 1.20.0.** Additive: `ClaimRecord.decision.erroredFacts` and
|
|
@@ -7754,14 +7754,14 @@ components:
|
|
|
7754
7754
|
maxTimeoutSeconds: 120
|
|
7755
7755
|
extra:
|
|
7756
7756
|
nonce: 7c1e2a4b-9d3f-4e8a-b6c5-2f1d0e9a8b7c
|
|
7757
|
-
fundingUrl: https://console.ixo.earth/credits
|
|
7757
|
+
fundingUrl: https://console.ixo.earth/billing/credits
|
|
7758
7758
|
price:
|
|
7759
7759
|
amountMicroUsd: 1200000
|
|
7760
7760
|
amountCents: 120
|
|
7761
7761
|
currency: USD
|
|
7762
7762
|
amount: "1200000"
|
|
7763
7763
|
asset: upay
|
|
7764
|
-
fundingUrl: https://console.ixo.earth/credits
|
|
7764
|
+
fundingUrl: https://console.ixo.earth/billing/credits
|
|
7765
7765
|
docsUrl: https://console.ixo.earth/docs/errors#PAYMENT_REQUIRED
|
|
7766
7766
|
SPEND_CAP:
|
|
7767
7767
|
value:
|
|
@@ -7777,7 +7777,7 @@ components:
|
|
|
7777
7777
|
currency: USD
|
|
7778
7778
|
amount: "1200000"
|
|
7779
7779
|
asset: upay
|
|
7780
|
-
fundingUrl: https://console.ixo.earth/credits
|
|
7780
|
+
fundingUrl: https://console.ixo.earth/billing/credits
|
|
7781
7781
|
docsUrl: https://console.ixo.earth/docs/errors#SPEND_CAP
|
|
7782
7782
|
INSUFFICIENT_CREDITS:
|
|
7783
7783
|
value:
|
|
@@ -7793,7 +7793,7 @@ components:
|
|
|
7793
7793
|
currency: USD
|
|
7794
7794
|
amount: "1200000"
|
|
7795
7795
|
asset: upay
|
|
7796
|
-
fundingUrl: https://console.ixo.earth/credits
|
|
7796
|
+
fundingUrl: https://console.ixo.earth/billing/credits
|
|
7797
7797
|
docsUrl: https://console.ixo.earth/docs/errors#INSUFFICIENT_CREDITS
|
|
7798
7798
|
NotFound:
|
|
7799
7799
|
description: "`NOT_FOUND` — unknown, or another source's (never 403 across sources)."
|
package/package.json
CHANGED
package/skills/README.md
CHANGED
|
@@ -17,3 +17,5 @@ installed package (leaving any skill of your own in that directory alone).
|
|
|
17
17
|
|
|
18
18
|
`reference/engine-contract.md` (here, beside the skills) is the decision engine's contract —
|
|
19
19
|
background for all eight, not an interface anyone codes against.
|
|
20
|
+
`reference/linked-docs.md` is the linked-document rules: where an entity's documents are uploaded,
|
|
21
|
+
each proof's format, and how to read one.
|
|
@@ -21,7 +21,7 @@ and wait for their OK. Dry-run every chain step first (`create-oracle` step 8's
|
|
|
21
21
|
## The adapter (copy, don't rewrite)
|
|
22
22
|
|
|
23
23
|
Source of truth: `examples/street-check-oracle` in the eval-oracle repo (an `init` project with
|
|
24
|
-
the adapter added, deployed on devnet)
|
|
24
|
+
the adapter added, deployed on devnet). Copy:
|
|
25
25
|
|
|
26
26
|
| Path | What it is |
|
|
27
27
|
| --- | --- |
|
|
@@ -48,20 +48,23 @@ bun run db:migrate:remote # must apply BOTH databases — copy th
|
|
|
48
48
|
bun run cf-typegen && bun run check
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
## Pricing —
|
|
51
|
+
## Pricing — set it deliberately per env
|
|
52
52
|
|
|
53
53
|
`src/pricing.ts` `CHECK_PRICE_DENOM` / `CHECK_PRICE_AMOUNT` feed `pricing.evaluation` AND the
|
|
54
|
-
ceiling written on every minted grant. Denom = the app's
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
`
|
|
59
|
-
|
|
54
|
+
ceiling written on every minted grant. Denom = the app's ask denom (`uixo` on devnet, `upay` on
|
|
55
|
+
testnet/mainnet). In a template project the `EVALUATION_DENOM` / `EVALUATION_MIN_AMOUNT` vars in
|
|
56
|
+
`wrangler.jsonc` override `pricing.evaluation` for that env — so set `EVALUATION_DENOM=upay` and
|
|
57
|
+
`EVALUATION_MIN_AMOUNT=<the check price>` in the testnet AND mainnet envs (mainnet will not boot
|
|
58
|
+
without them), or `EVALUATION_MIN_AMOUNT=0` for an oracle IXO bills per review (its collections
|
|
59
|
+
carry an empty evaluation leg). Outside per-review billing, 0 means the oracle works for free while
|
|
60
|
+
the engine bills its owner per decision. The picker shows the price from `/v1/info`, and the
|
|
61
|
+
poster's escrow carries it; an ask escrowing less is refused 402 and never judged. Default, unless
|
|
62
|
+
the provider names one: `350_000` base units — 0.35 IXO on devnet, 0.35 PAY ($0.35) on
|
|
63
|
+
testnet/mainnet, Openhands' own check fee, which covers the engine's $0.30 per decision.
|
|
60
64
|
|
|
61
65
|
## Being listed and hired
|
|
62
66
|
|
|
63
|
-
The app's picker
|
|
64
|
-
UNSET) lists an oracle when its entity has: `#acard` with a **`check-openhands`** service (next to
|
|
67
|
+
The app's picker lists an oracle when its entity has: `#acard` with a **`check-openhands`** service (next to
|
|
65
68
|
`check-measure`, priced in PAY — the app reads the service id, and `check-openhands` is what marks
|
|
66
69
|
the oracle Openhands-compatible); `#orz` granting `ORACLE_ADDRESS`; `#eval` = an https base URL
|
|
67
70
|
whose `/v1/info` answers that address, the ask denom, and `policies.allowAiChecks: true` (else it
|
|
@@ -77,10 +80,8 @@ bunx decision-oracle oracle init --protocol <any ask's protocol, or the app's cl
|
|
|
77
80
|
--kit-url https://<host> --logo https://<host>/logo.svg --openhands --network <n> # dry run; then --yes
|
|
78
81
|
```
|
|
79
82
|
|
|
80
|
-
Hire/scan nudges go to the PICKED oracle's `#eval`;
|
|
81
|
-
|
|
82
|
-
`#eval` endpoint and `app/ask/post.ts` passes `checker.endpoint` to `notifyOracle` — and in use,
|
|
83
|
-
when the hire nudge shows up in THIS oracle's logs after a post.
|
|
83
|
+
Hire/scan nudges go to the PICKED oracle's `#eval`; you know the app routes to you when the hire
|
|
84
|
+
nudge shows up in THIS oracle's logs after a post.
|
|
84
85
|
|
|
85
86
|
Then, right after deploy: `bunx decision-oracle engine register --env <env> --env-file .dev.vars`.
|
|
86
87
|
The Openhands app lists only registered oracles, and otherwise the engine (and the Decision
|
|
@@ -105,9 +106,9 @@ Console) learns the oracle only at its first decision.
|
|
|
105
106
|
| --- | --- |
|
|
106
107
|
| Hire nudge 404 | the adapter's routes are not wrapped in `src/index.ts` `fetch` |
|
|
107
108
|
| Every claim rejected `weather` "unreachable" | `weather` left as a stub; copy `src/facts/weather.ts` (Open-Meteo, no key) |
|
|
108
|
-
| Oracle missing from the picker | no `check-openhands` service on `#acard`, no `#orz`/https `#eval`, not `engine register`ed,
|
|
109
|
-
| Picker shows the oracle at 0 | `pricing.ts` still 0, or
|
|
109
|
+
| Oracle missing from the picker | no `check-openhands` service on `#acard`, no `#orz`/https `#eval`, not `engine register`ed, or its price unreadable |
|
|
110
|
+
| Picker shows the oracle at 0 | `pricing.ts` / that env's `EVALUATION_MIN_AMOUNT` still 0 on an oracle not billed per review, or the denom ≠ the ask denom |
|
|
110
111
|
| `withinRadius` fails for everyone | the ask's place was geocoded from a word ("You" → a village in Burkina Faso); set the place by name |
|
|
111
112
|
| Console "Could not read this oracle's prices" | the console reads the Decision API price list; a chain-lane oracle has none (`API_LANE` off) — console-side, not an oracle fault |
|
|
112
|
-
| Wrangler can't resolve `protobufjs/minimal.js` | inside the eval-oracle workspace there is one hoisted protobufjs; drop
|
|
113
|
+
| Wrangler can't resolve `protobufjs/minimal.js` | inside the eval-oracle workspace there is one hoisted protobufjs; drop any protobufjs `alias` you copied in |
|
|
113
114
|
| `chain.test.ts` fails after a denom change | the "foreign denom" fixtures used your new denom; give them one you are not paid in |
|
|
@@ -60,11 +60,13 @@ protocol.
|
|
|
60
60
|
`create-deed` refuses a protocol without one)
|
|
61
61
|
- the deed: an existing domain entity DID that already links the protocol, OR a title (+ optional
|
|
62
62
|
description) for a new one — the title is what the portal's picker shows
|
|
63
|
-
- evaluation payment: denom + amount. This is the oracle's income per decision AND the
|
|
64
|
-
that oracle
|
|
65
|
-
oracle rather than guessing
|
|
63
|
+
- evaluation payment: denom + amount. This is the oracle's income per decision AND must meet the
|
|
64
|
+
minimum that oracle accepts (its `EVALUATION_DENOM` / `EVALUATION_MIN_AMOUNT`), so confirm the
|
|
65
|
+
number with whoever owns the oracle rather than guessing
|
|
66
66
|
- optional admin funding amount (`--fund`) — covers the first evaluation payouts, see the gotcha
|
|
67
67
|
- the oracle address to grant Evaluate; the agent address(es) to grant Submit (comma-separated)
|
|
68
|
+
— `--submit addr1,addr2` is also how to restrict who may claim, e.g. a payouts collection only
|
|
69
|
+
two people may submit to
|
|
68
70
|
- quota and window in days if the defaults (100, 90) aren't right — state them explicitly rather
|
|
69
71
|
than silently applying them
|
|
70
72
|
|
|
@@ -94,6 +96,10 @@ protocol.
|
|
|
94
96
|
[--max-custom-amount 0uixo] [--phase collection|fund|grants|all] [--yes]
|
|
95
97
|
```
|
|
96
98
|
|
|
99
|
+
`--eval-denom` must equal the oracle's `EVALUATION_DENOM` — on mainnet the USDC ibc denom or
|
|
100
|
+
`upay`, never `uixo`. `--eval-amount 0` writes an EMPTY evaluation leg (the chain refuses a zero
|
|
101
|
+
coin): that is what a collection for a per-review-billed or 0-minimum oracle registers with.
|
|
102
|
+
|
|
97
103
|
`--max-custom-amount` is the evaluate grant's `MaxCustomAmount`, written explicitly (`0<eval
|
|
98
104
|
denom>` by default). The chain holds EVERY non-empty evaluation amount to it (its denom must be
|
|
99
105
|
listed), and the oracle sends an ordinary claim's own coins by default — so if the protocol's
|
|
@@ -161,6 +167,12 @@ protocol.
|
|
|
161
167
|
|
|
162
168
|
7. **Report the run** — the output contract below.
|
|
163
169
|
|
|
170
|
+
Payout ASKS (a deed or request with its organisation links and `#payoutTerms`) are posted only
|
|
171
|
+
through OpenHands, not with these commands. A company paying people from its OWN collection runs
|
|
172
|
+
its own self-hosted payouts facilitator instead: enable the collection there
|
|
173
|
+
(`/v1/payouts/collections`) with a `fromDecision` rule on `$.<amount field>`, and name the same
|
|
174
|
+
amount field and currency in the oracle's `payouts` config.
|
|
175
|
+
|
|
164
176
|
## Output contract
|
|
165
177
|
|
|
166
178
|
Always end with this block, verbatim, filled in from this run:
|
|
@@ -187,7 +199,8 @@ account, a phase that was dry-run but never confirmed, or a delegation nobody ha
|
|
|
187
199
|
| Creating the collection before the deed links the protocol | run `create-deed --phase claims`; the picker reads `linkedClaim` → claims-config |
|
|
188
200
|
| Granting Evaluate and expecting the oracle to pull claims | it also needs the claim-bot delegation (step 5) |
|
|
189
201
|
| Leaving the admin account unfunded | every evaluation debits it, rejects included — pass `--fund` |
|
|
190
|
-
| Guessing the evaluation amount | it must meet the oracle's `
|
|
202
|
+
| Guessing the evaluation amount | it must meet the oracle's `EVALUATION_MIN_AMOUNT` in its `EVALUATION_DENOM`, or register 402s |
|
|
203
|
+
| `--eval-amount 0` expecting a zero coin | it writes an empty evaluation leg — right only for a per-review-billed or 0-minimum oracle |
|
|
191
204
|
| Running with `--yes` first | dry-run, show the plan, then confirm |
|
|
192
205
|
| Re-running `create-deed --phase claims` for no reason | it rewrites the doc under a new cid and adds a second `linkedClaim` — resume from `claims` only when that phase actually failed |
|
|
193
206
|
|
|
@@ -36,7 +36,8 @@ First the portal's gate: `--entity` must not be a protocol, must have a `linkedC
|
|
|
36
36
|
the protocol, `startDate` = now − 1 day, `endDate` = now + `--days`, `quota`, and four payment legs
|
|
37
37
|
(submission / approval / rejection / evaluation), each `Payment{ account: <deed admin>, amount,
|
|
38
38
|
isOraclePayment: false }` — only `evaluation` carries a nonzero amount (`--eval-amount` /
|
|
39
|
-
`--eval-denom`); the other three legs are empty. `
|
|
39
|
+
`--eval-denom`); the other three legs are empty. With `--eval-amount 0` all four are empty — the
|
|
40
|
+
chain refuses a zero coin, so `0` means no evaluation payment at all. `isOraclePayment` is never turned on by this command
|
|
40
41
|
on ANY leg: the chain rule is that it is only ever legal on the approval leg, so setting it on
|
|
41
42
|
evaluation would be a protocol violation. After signing, it polls Blocksync for a few seconds waiting
|
|
42
43
|
for the new collection to index before moving on to fund/grants.
|
|
@@ -17,6 +17,33 @@ a protocol's rubric declares (`bunx decision-oracle protocol review <did>`); thi
|
|
|
17
17
|
those names and nothing else. It never parses a rubric, never binds a form, never decides. If the
|
|
18
18
|
manifest is `unusable`, there is nothing to build against yet — stop and say so.
|
|
19
19
|
|
|
20
|
+
## Which skill do I need?
|
|
21
|
+
|
|
22
|
+
Run an oracle for a protocol → this skill. Write the code that answers each fact → `write-facts`.
|
|
23
|
+
Write the rules claims are judged by → `create-rubric`. Put a claim form and its rules on chain →
|
|
24
|
+
`publish-protocol`. Open a place for claims to be submitted and hire an oracle on it →
|
|
25
|
+
`create-collection`. Let apps and agents ask the oracle for decisions over HTTP →
|
|
26
|
+
`decision-api-oracle`; test that from the customer's side → `decision-api-client`. Be hireable from
|
|
27
|
+
the Openhands app → `add-openhands-support`.
|
|
28
|
+
|
|
29
|
+
**Words used throughout:**
|
|
30
|
+
|
|
31
|
+
- **Oracle** — the service this package is: it gathers the evidence for each claim and asks the
|
|
32
|
+
engine for a verdict.
|
|
33
|
+
- **Protocol** — a published kind of claim: the form people fill in plus the rules it is judged by.
|
|
34
|
+
- **Rubric** — those rules, written down: what counts as approve, reject or "needs a person".
|
|
35
|
+
- **Claim** — one submission: someone's answers (and files) on a protocol's form.
|
|
36
|
+
- **Collection** — a place on chain where claims for one protocol are submitted and paid for.
|
|
37
|
+
- **Engine** — IXO's decision engine: it reads the facts your oracle sends and gives the verdict.
|
|
38
|
+
- **Decision / receipt** — the engine's verdict, and its signed proof that it gave it; the oracle
|
|
39
|
+
records both and puts the proof on chain.
|
|
40
|
+
- **PAY / `upay`** — IXO's US-dollar token (1 PAY = 1 USD); `upay` is its smallest unit, a
|
|
41
|
+
millionth of a PAY.
|
|
42
|
+
- **did:web** — this oracle's web identity, a name tied to its domain; other services check its
|
|
43
|
+
signatures by fetching `https://<host>/.well-known/did.json`.
|
|
44
|
+
- **Delegation** — a signed permission one party gives another, such as the owner letting the engine
|
|
45
|
+
bill their subscription, or letting the oracle read their claims.
|
|
46
|
+
|
|
20
47
|
## When to use
|
|
21
48
|
|
|
22
49
|
- "Build / set up / configure an oracle for protocol X", "what would my oracle need to produce"
|
|
@@ -86,11 +113,18 @@ and any `ERROR: this source will not be called` (the audience is not the endpoin
|
|
|
86
113
|
the name shows as `refused: fix the rubric`, the command exits 1, and only the protocol owner can fix
|
|
87
114
|
it; no handler stands in). Then fill in `src/index.ts` with the provider's answers (the interview
|
|
88
115
|
table below):
|
|
89
|
-
`supportedProtocols: ["<protocol did>"]`,
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
116
|
+
`supportedProtocols: ["<protocol did>"]`, the evaluation fee, and `policies`.
|
|
117
|
+
|
|
118
|
+
The fee is the on-chain evaluation payment a collection must carry, or register refuses it. Set it
|
|
119
|
+
per wrangler env with the `EVALUATION_DENOM` / `EVALUATION_MIN_AMOUNT` vars (both or neither; the
|
|
120
|
+
minimum in integer base units) — they replace `pricing.evaluation` from `defineOracle`, and they
|
|
121
|
+
are REQUIRED on mainnet: the worker refuses to start without them. A third-party oracle typically
|
|
122
|
+
charges Noble USDC (`ibc/6BBE9BD4246F8E04948D5A4EEE7164B2630263B9EBB5E7DC5F0A46C62A2FF97B`); an
|
|
123
|
+
IXO-managed oracle billed per review uses `upay` / `0`, which accepts a collection whose evaluation
|
|
124
|
+
leg is empty. `pricing.byProtocol` still wins for the protocols it names. The effective price is
|
|
125
|
+
what `GET /v1/info` shows as `pricing`.
|
|
126
|
+
|
|
127
|
+
The `policies`: `allowAiChecks` true iff anything asks for a model (an `ai` check, or a `unique` rule
|
|
94
128
|
with its judge on), `allowImageChecks` true iff a check reads a photo and the provider wants C2PA
|
|
95
129
|
screening, `autoSign` true only when unattended chain writes are deliberate (the `AUTO_SIGN` var
|
|
96
130
|
gates it too — both must be on), and `allowStandingApprovals` — REQUIRED, no default: `true` lets a
|
|
@@ -158,6 +192,10 @@ printf 'OWNER_DELEGATION_CAR="%s"\n' "$(cat owner-delegation.car)" >> .dev.vars
|
|
|
158
192
|
before it lapses.
|
|
159
193
|
- Only the human can do the login. Run it in the background so the loopback callback lands, and tell
|
|
160
194
|
them to finish in the browser.
|
|
195
|
+
- **The owner must hold an IXO subscription before `engine register`**, or it answers 402
|
|
196
|
+
`NO_SUBSCRIPTION`. A subscription created by the subscriptions workflow (not the portal) also
|
|
197
|
+
needs a Stripe customer: the owner calls the subscriptions API's `POST /api/v1/payments/intent`
|
|
198
|
+
once (a SetupIntent — nothing is charged).
|
|
161
199
|
- **A 402 at register is the owner's credits, not a bug**: `NO_SUBSCRIPTION` (none at all) or
|
|
162
200
|
`INSUFFICIENT_CREDITS` (below one decision's price, carrying `manageSubscriptionUrl`). Send the
|
|
163
201
|
owner to that portal URL to buy credits, then register again — nothing here can fake it.
|
|
@@ -183,10 +221,11 @@ finds this oracle. One command does all of it:
|
|
|
183
221
|
|
|
184
222
|
```bash
|
|
185
223
|
bunx decision-oracle oracle init --protocol <protocol did> --kit-url http://localhost:8787 \
|
|
186
|
-
[--logo <url>] [--
|
|
224
|
+
[--logo <url>] [--openhands [--price-pay <n>]] [--only <step>] [--relogin] \
|
|
225
|
+
[--network <n>] [--yes]
|
|
187
226
|
```
|
|
188
227
|
|
|
189
|
-
**A full on-chain identity is mandatory
|
|
228
|
+
**A full on-chain identity is mandatory**: every oracle built with this kit gets
|
|
190
229
|
its entity, its `#pro` profile, its `#dmn` domain card and its `#acard` Agent Card — this command
|
|
191
230
|
does all four. `--logo <url>` is optional, but ASK the provider for one: without it the portal and
|
|
192
231
|
the console show a placeholder, and every run prints `⚠ recommended: --logo`.
|
|
@@ -260,7 +299,8 @@ where a live token would have skipped (it mints a new Matrix device — not a ca
|
|
|
260
299
|
### 9. Deploy it
|
|
261
300
|
|
|
262
301
|
```bash
|
|
263
|
-
bun run db:migrate:remote # BEFORE the first deploy of
|
|
302
|
+
bun run db:migrate:remote # BEFORE the first deploy of the default env; for a named env:
|
|
303
|
+
# bunx wrangler d1 migrations apply DB --remote --env <env>
|
|
264
304
|
bun run deploy # or deploy:testnet / deploy:production
|
|
265
305
|
wrangler secret put ORACLE_MATRIX_ACCESS_TOKEN # the value step 8 wrote into .dev.vars
|
|
266
306
|
```
|
|
@@ -308,18 +348,20 @@ bunx decision-oracle register --collection <collection id> [--delegation delegat
|
|
|
308
348
|
bunx decision-oracle scan --collection <collection id> # discover claims now, not at the next tick
|
|
309
349
|
```
|
|
310
350
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
claim
|
|
314
|
-
|
|
315
|
-
|
|
351
|
+
Claim bodies are pulled from the VFS claims lane first (under the oracle's own Evaluate grant), then
|
|
352
|
+
the Matrix claim bot, then the IPFS gateway or a declared cellnode. `--delegation` is the
|
|
353
|
+
owner→oracle claim-bot CAR (`delegation --for bot --audience did:ixo:<ORACLE_ADDRESS>`); it matters
|
|
354
|
+
only for claims stored in Matrix — without it those bodies cannot be pulled. A refusal names its
|
|
355
|
+
gate — not the chain owner, no Evaluate grant for `ORACLE_ADDRESS`, or an evaluation payment below
|
|
356
|
+
the required fee (`pricing.byProtocol` for that collection's protocol, else the env's
|
|
357
|
+
`EVALUATION_MIN_AMOUNT`).
|
|
316
358
|
|
|
317
359
|
## Interview slots (ask, don't assume)
|
|
318
360
|
|
|
319
361
|
| Slot | Ask | Lands in |
|
|
320
362
|
| --- | --- | --- |
|
|
321
363
|
| Protocol | the DID, and which network | `--protocol`, `supportedProtocols` |
|
|
322
|
-
| Pricing | denom + minimum per-evaluation payment; any protocol priced differently (incl. free)? | `
|
|
364
|
+
| Pricing | denom + minimum per-evaluation payment per network; any protocol priced differently (incl. free)? | `EVALUATION_DENOM` / `EVALUATION_MIN_AMOUNT` per env, optionally `pricing.byProtocol` |
|
|
323
365
|
| AI / image policy | does the work order declare `ai` checks; do any read images | `policies.allowAiChecks` / `allowImageChecks` |
|
|
324
366
|
| Auto-sign | should this oracle sign `MsgEvaluateClaim` unattended | `policies.autoSign` + the `AUTO_SIGN` var |
|
|
325
367
|
| Standing approvals | may a signed-in AI app's own auto-approve limits pay without a per-claim approval (hosted MCP) — IXO's own oracles say yes | `policies.allowStandingApprovals` (required) |
|
|
@@ -352,7 +394,8 @@ collection's protocol, else `pricing.evaluation.minAmount`).
|
|
|
352
394
|
| Register answers 402 and the agent retries | it is the owner's credits — send them to the printed portal URL, then re-run |
|
|
353
395
|
| `.dev.vars` edited but the old value still in play | a running `wrangler dev` reloads source, not secrets — restart it |
|
|
354
396
|
| `ORACLE_ADDRESS` typed by hand | must match the mnemonic exactly — asserted at first use |
|
|
355
|
-
| Guessing `
|
|
397
|
+
| Guessing `EVALUATION_MIN_AMOUNT` | ask what the collection's on-chain evaluation payment is (or will be) — set too high and register 402s |
|
|
398
|
+
| No `EVALUATION_DENOM` in the mainnet env | the worker refuses to start — set both vars in every env you deploy |
|
|
356
399
|
| `allowAiChecks: false` while the work order declares AI checks | every `ai` fact freezes `error` and the rubric's `onError` decides — ask first |
|
|
357
400
|
| `ORACLE_HOSTNAME` ≠ the deployed Custom Domain | callers resolve the did:web by fetching that host — they must be the same string |
|
|
358
401
|
| `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 |
|
|
@@ -360,7 +403,7 @@ collection's protocol, else `pricing.evaluation.minAmount`).
|
|
|
360
403
|
| Skipping `--logo` without asking | the identity is still complete, but the portal and the console show a placeholder — ask the provider for a logo URL and pass `--logo` |
|
|
361
404
|
| Not re-running `oracle init` after the deploy | `#eval` and both cards still name `localhost` and `#pro` may be missing — re-run with the deployed `--kit-url` and `--yes` |
|
|
362
405
|
| Treating `⚠ domain indexer …` as a failure | it is a warning and the exit code is 0 — the entity is on chain either way |
|
|
363
|
-
| Registering with the on-chain grant but no claim-bot delegation |
|
|
406
|
+
| Registering with the on-chain grant but no claim-bot delegation | Matrix-stored claims can't be pulled — mint `delegation --for bot` and pass `--delegation` |
|
|
364
407
|
|
|
365
408
|
## Worked example
|
|
366
409
|
|
|
@@ -389,6 +432,8 @@ restart, re-register. Restart both dev servers after any `.dev.vars` edit.
|
|
|
389
432
|
default and cap; the routes, cron lanes, pause reasons and billing the package already owns).
|
|
390
433
|
- `../reference/engine-contract.md` — the engine's side: register, the error table, billing,
|
|
391
434
|
receipts, review folds. Background, not an interface.
|
|
435
|
+
- `../reference/linked-docs.md` — the linked-document rules: Vault first, the IXO IPFS gateway as
|
|
436
|
+
the fallback, each proof's format, and `readLinkedDoc`.
|
|
392
437
|
|
|
393
438
|
## Output contract
|
|
394
439
|
|
|
@@ -93,8 +93,9 @@ default here is the author's call — ask.
|
|
|
93
93
|
|
|
94
94
|
## Rules that bite (the engine's, not opinions)
|
|
95
95
|
|
|
96
|
-
- `claimSchema.proof` is the chain's `#vct` proof copied verbatim
|
|
97
|
-
|
|
96
|
+
- `claimSchema.proof` is the chain's `#vct` proof copied verbatim, compared as a string — sha256 hex
|
|
97
|
+
for a protocol published with the CLI, a CID for one published through the Portal. Never
|
|
98
|
+
computed.
|
|
98
99
|
- File content is never machine-judged: presence / type / size only. "Does the photo show X" is
|
|
99
100
|
`ManualScore` + `ReviewTask`, `answer` boolean or enum, `map` covering every answer — or an
|
|
100
101
|
`aiChecks` entry, which an oracle answers.
|
|
@@ -16,7 +16,7 @@ format still shows `constants` / `@const` refs; those do not exist (inline liter
|
|
|
16
16
|
"@type": "Rubric",
|
|
17
17
|
"title": "…", "description": "…", // display-only
|
|
18
18
|
"claimSchema": { "@type": "ClaimSchemaBinding", "protocol": "did:ixo:entity:…", "resource": "#vct",
|
|
19
|
-
"proof": "<the protocol's #vct LinkedResource proof, VERBATIM — a CID, compared as a string>" },
|
|
19
|
+
"proof": "<the protocol's #vct LinkedResource proof, VERBATIM — sha256 hex (CLI) or a CID (Portal), compared as a string>" },
|
|
20
20
|
"derived": [ … ], "gates": [ … ], "scoring": { … }, "review": { … }, "settlement": { … },
|
|
21
21
|
"sources": [ … ], "aiChecks": [ … ], "unique": { … }, "frequency": { … }
|
|
22
22
|
}
|