@ixo/decision-oracle 0.2.34 → 0.3.0

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.
Files changed (52) hide show
  1. package/README.md +3 -1
  2. package/dist/app.d.ts.map +1 -1
  3. package/dist/app.js +12 -4
  4. package/dist/app.js.map +1 -1
  5. package/dist/cli/commands/facts-run.d.ts +3 -2
  6. package/dist/cli/commands/facts-run.d.ts.map +1 -1
  7. package/dist/cli/commands/facts-run.js +52 -108
  8. package/dist/cli/commands/facts-run.js.map +1 -1
  9. package/dist/config.d.ts +12 -0
  10. package/dist/config.d.ts.map +1 -1
  11. package/dist/config.js +19 -0
  12. package/dist/config.js.map +1 -1
  13. package/dist/env.d.ts +5 -0
  14. package/dist/env.d.ts.map +1 -1
  15. package/dist/lib/facts/builder.d.ts +4 -9
  16. package/dist/lib/facts/builder.d.ts.map +1 -1
  17. package/dist/lib/facts/builder.js +12 -41
  18. package/dist/lib/facts/builder.js.map +1 -1
  19. package/dist/lib/facts/deps.d.ts +15 -0
  20. package/dist/lib/facts/deps.d.ts.map +1 -0
  21. package/dist/lib/facts/deps.js +37 -0
  22. package/dist/lib/facts/deps.js.map +1 -0
  23. package/dist/lib/facts/preview.d.ts +34 -0
  24. package/dist/lib/facts/preview.d.ts.map +1 -0
  25. package/dist/lib/facts/preview.js +46 -0
  26. package/dist/lib/facts/preview.js.map +1 -0
  27. package/dist/lib/openhands/why.d.ts +11 -0
  28. package/dist/lib/openhands/why.d.ts.map +1 -1
  29. package/dist/lib/openhands/why.js +32 -26
  30. package/dist/lib/openhands/why.js.map +1 -1
  31. package/dist/middleware/capability.d.ts +1 -1
  32. package/dist/middleware/capability.d.ts.map +1 -1
  33. package/dist/middleware/capability.js +4 -0
  34. package/dist/middleware/capability.js.map +1 -1
  35. package/dist/routes/v1/admin.d.ts.map +1 -1
  36. package/dist/routes/v1/admin.js +2 -1
  37. package/dist/routes/v1/admin.js.map +1 -1
  38. package/dist/routes/v1/index.d.ts.map +1 -1
  39. package/dist/routes/v1/index.js +2 -0
  40. package/dist/routes/v1/index.js.map +1 -1
  41. package/dist/routes/v1/practice.d.ts +39 -0
  42. package/dist/routes/v1/practice.d.ts.map +1 -0
  43. package/dist/routes/v1/practice.js +320 -0
  44. package/dist/routes/v1/practice.js.map +1 -0
  45. package/dist/workflows/evaluate.d.ts.map +1 -1
  46. package/dist/workflows/evaluate.js +2 -1
  47. package/dist/workflows/evaluate.js.map +1 -1
  48. package/docs/api.md +4 -1
  49. package/docs/guide.md +52 -0
  50. package/package.json +1 -1
  51. package/templates/project/.dev.vars.example +3 -0
  52. package/templates/project/wrangler.jsonc +9 -0
package/docs/guide.md CHANGED
@@ -1111,6 +1111,58 @@ Three things to decide:
1111
1111
  oracle's claims. Register the oracle with an account you will NOT use to post or review asks
1112
1112
  (a company or service login), so you can still answer reviews yourself.
1113
1113
 
1114
+ ### Practice checks
1115
+
1116
+ An app can let a person see what your oracle **would** decide on their completion before they hand
1117
+ it in. `POST /v1/practice-check` runs the same build a real claim runs — your facts table, the real
1118
+ tools, the real AI, the collection's real window, `now` as the clock and the person's address as the
1119
+ claim's signer — and asks the engine's preview route what it would decide. Nothing is kept: no
1120
+ claim, no chain write, no fee, no grant, no duplicate-registry row, no review task, no email, and the
1121
+ engine bills nothing. Only the AI spend is recorded, as a real check's is (`ai.tokens`, and
1122
+ `ai_calls` rows under a `practice-<uuid>` claim id), so you can see what practice costs you.
1123
+
1124
+ It is off until you name the apps allowed to call it. Each is a server with its own key, calling
1125
+ with a UCAN `practice/check` (strict: never `*`) addressed to your oracle's `did:web`, like every
1126
+ other `/v1` route:
1127
+
1128
+ ```jsonc
1129
+ // wrangler.jsonc, every env
1130
+ "PRACTICE_CHECK_CALLERS": "did:web:<app host>",
1131
+ // optional daily limits (defaults shown), each per UTC day
1132
+ "PRACTICE_CHECK_LIMIT_ASK": "5", // per person per collection
1133
+ "PRACTICE_CHECK_LIMIT_SUBMITTER": "30", // per person, every collection
1134
+ "PRACTICE_CHECK_LIMIT_ORACLE": "500", // your whole oracle: the cost backstop
1135
+ ```
1136
+
1137
+ ```http
1138
+ POST /v1/practice-check
1139
+ { "collectionId": "1234", "submitter": "ixo1…", "answers": { … },
1140
+ "attachments": [{ "question": "photo", "name": "a.jpg", "mediaType": "image/jpeg",
1141
+ "dataUrl": "data:image/jpeg;base64,…" }] }
1142
+
1143
+ 200 { "outcome": "approve" | "review" | "reject",
1144
+ "reasons": [{ "code": "G-1", "outcome": "passed" | "failed" | "review", "reason": "…" }],
1145
+ "notes": ["…"], "limits": { "remaining": 4, "resetsAt": "…" } }
1146
+ ```
1147
+
1148
+ `reasons` carries your rubric's own sentence for each gate and criterion; `notes` is what a reviewer
1149
+ would read (your reviewer note, when the oracle makes one — one more model call). When your rubric
1150
+ holds every claim for a person's final OK, `review` is the normal good answer. A spent limit is `429`
1151
+ with `retryAfter` and `limits`; an engine or AI that cannot answer is `502` / `503`, never a verdict.
1152
+
1153
+ What is not the same as a real claim, and fails closed:
1154
+
1155
+ - **The stock duplicate check** registers a claim before it compares, so it does not run: the dry-run
1156
+ placeholder (the same one `facts run` uses, band `review`) answers instead, and `notes` says so. A
1157
+ rubric with a `unique` rule therefore previews `review` at best. A `facts.unique` handler of your
1158
+ own still runs — keep it free of writes.
1159
+ - **Attachments** arrive inline as `data:` URLs (up to 20 files, a 10 MB body) with no CID, so a
1160
+ handler that reads `att.cid` sees none.
1161
+ - **The frequency count** adds the would-be claim to what Blocksync counts, as the real claim's own
1162
+ count would include it.
1163
+
1164
+ api.md §12 has the full contract.
1165
+
1114
1166
  ### Third-party oracle fees
1115
1167
 
1116
1168
  An oracle that IXO does not run is paid on chain claims by the collection's on-chain **evaluation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ixo/decision-oracle",
3
- "version": "0.2.34",
3
+ "version": "0.3.0",
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": [
@@ -76,6 +76,9 @@ UNIQUE_HMAC_KEY="change-me-to-a-long-random-string"
76
76
  # status board), by its DID of any method. Not a secret — deployed, it lives in wrangler.jsonc `vars`;
77
77
  # set it here only to try it under `wrangler dev`. Unset ⇒ only ORACLE_ADMIN_DIDS can read the status.
78
78
  # STATUS_READER_DIDS="did:web:<monitor host>"
79
+ # Callers of POST /v1/practice-check (an app's server, by its DID of any method). Not a secret —
80
+ # deployed, it lives in wrangler.jsonc `vars`. Unset ⇒ the route is off (404).
81
+ # PRACTICE_CHECK_CALLERS="did:web:<app host>"
79
82
 
80
83
  # --- Local dev logging ---
81
84
  # Pretty, colorized log lines for the terminal. Local-only: this file is never
@@ -220,6 +220,12 @@
220
220
  // Read-only access to GET /v1/admin/status for a monitoring service (any DID method, e.g. your
221
221
  // decision engine's status board by its did:web). Never an oracle admin: it reaches nothing else.
222
222
  // "STATUS_READER_DIDS": "did:web:<monitor host>",
223
+ // Callers of POST /v1/practice-check (an app's server, e.g. asks.world's did:web): what this oracle
224
+ // WOULD decide on a completion, nothing persisted. Unset ⇒ the route is off. Daily limits below.
225
+ // "PRACTICE_CHECK_CALLERS": "did:web:<app host>",
226
+ // "PRACTICE_CHECK_LIMIT_ASK": "5",
227
+ // "PRACTICE_CHECK_LIMIT_SUBMITTER": "30",
228
+ // "PRACTICE_CHECK_LIMIT_ORACLE": "500",
223
229
 
224
230
  // The From address/name on pause, resume and review notices. Unset ⇒ the email lane logs once
225
231
  // and skips. Commented, not blank: an empty string fails config validation.
@@ -281,6 +287,7 @@
281
287
  // "AUTH_HUB_URL": "https://<authhub host>",
282
288
  // "ORACLE_ADMIN_DIDS": "did:ixo:<admin>",
283
289
  // "STATUS_READER_DIDS": "did:web:<monitor host>",
290
+ // "PRACTICE_CHECK_CALLERS": "did:web:<app host>",
284
291
 
285
292
  // "EMAIL_FROM_ADDRESS": "oracle@your-domain",
286
293
  // "EMAIL_FROM_NAME": "Your Oracle",
@@ -392,6 +399,7 @@
392
399
  // "AUTH_HUB_URL": "https://<authhub host>",
393
400
  // "ORACLE_ADMIN_DIDS": "did:ixo:<admin>",
394
401
  // "STATUS_READER_DIDS": "did:web:<monitor host>",
402
+ // "PRACTICE_CHECK_CALLERS": "did:web:<app host>",
395
403
 
396
404
  // "EMAIL_FROM_ADDRESS": "oracle@your-domain",
397
405
  // "EMAIL_FROM_NAME": "Your Oracle",
@@ -503,6 +511,7 @@
503
511
  // "AUTH_HUB_URL": "https://<authhub host>",
504
512
  // "ORACLE_ADMIN_DIDS": "did:ixo:<admin>",
505
513
  // "STATUS_READER_DIDS": "did:web:<monitor host>",
514
+ // "PRACTICE_CHECK_CALLERS": "did:web:<app host>",
506
515
 
507
516
  // "EMAIL_FROM_ADDRESS": "oracle@your-domain",
508
517
  // "EMAIL_FROM_NAME": "Your Oracle",