@ixo/decision-oracle 0.2.27 → 0.2.29
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 +1 -1
- package/dist/db/schema.d.ts +17 -0
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +10 -0
- package/dist/db/schema.js.map +1 -1
- package/dist/lib/api-lane/accept.d.ts.map +1 -1
- package/dist/lib/api-lane/accept.js +27 -10
- package/dist/lib/api-lane/accept.js.map +1 -1
- package/dist/lib/api-lane/notify.d.ts +9 -0
- package/dist/lib/api-lane/notify.d.ts.map +1 -1
- package/dist/lib/api-lane/notify.js +10 -3
- package/dist/lib/api-lane/notify.js.map +1 -1
- package/dist/lib/api-lane/record.d.ts.map +1 -1
- package/dist/lib/api-lane/record.js +6 -3
- package/dist/lib/api-lane/record.js.map +1 -1
- package/dist/lib/engine/client.d.ts +14 -2
- package/dist/lib/engine/client.d.ts.map +1 -1
- package/dist/lib/engine/client.js +90 -11
- package/dist/lib/engine/client.js.map +1 -1
- package/dist/lib/work-order/index.d.ts +4 -2
- package/dist/lib/work-order/index.d.ts.map +1 -1
- package/dist/lib/work-order/index.js +19 -4
- package/dist/lib/work-order/index.js.map +1 -1
- package/dist/middleware/api/keys.d.ts.map +1 -1
- package/dist/middleware/api/keys.js +10 -2
- package/dist/middleware/api/keys.js.map +1 -1
- package/dist/middleware/api/rate-limit.js +3 -4
- package/dist/middleware/api/rate-limit.js.map +1 -1
- package/dist/middleware/api/wait.d.ts +17 -2
- package/dist/middleware/api/wait.d.ts.map +1 -1
- package/dist/middleware/api/wait.js +80 -19
- package/dist/middleware/api/wait.js.map +1 -1
- package/dist/networks.d.ts +3 -0
- package/dist/networks.d.ts.map +1 -1
- package/dist/networks.js +3 -0
- package/dist/networks.js.map +1 -1
- package/dist/routes/v1/api/claims.d.ts +15 -3
- package/dist/routes/v1/api/claims.d.ts.map +1 -1
- package/dist/routes/v1/api/claims.js +85 -14
- package/dist/routes/v1/api/claims.js.map +1 -1
- package/dist/routes/v1/api/protocols.d.ts +1 -1
- package/dist/routes/v1/api/protocols.d.ts.map +1 -1
- package/dist/routes/v1/api/protocols.js +13 -20
- package/dist/routes/v1/api/protocols.js.map +1 -1
- package/dist/routes/v1/info.js +1 -1
- package/dist/routes/v1/info.js.map +1 -1
- package/dist/workflows/claim-ingest.d.ts +19 -125
- package/dist/workflows/claim-ingest.d.ts.map +1 -1
- package/dist/workflows/claim-ingest.js +49 -765
- package/dist/workflows/claim-ingest.js.map +1 -1
- package/dist/workflows/evaluate.d.ts +193 -0
- package/dist/workflows/evaluate.d.ts.map +1 -0
- package/dist/workflows/evaluate.js +980 -0
- package/dist/workflows/evaluate.js.map +1 -0
- package/docs/api.md +26 -6
- package/docs/guide.md +19 -1
- package/migrations/0029_inline_lease.sql +1 -0
- package/migrations/meta/0029_snapshot.json +3021 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +1 -1
|
@@ -4,10 +4,16 @@
|
|
|
4
4
|
* each step checkpointed and auto-retried, so a crash/redeploy/transient failure never re-does
|
|
5
5
|
* work or drops a claim.
|
|
6
6
|
*
|
|
7
|
-
* THE WORKFLOW OWNS ITS LEDGER ROW — one writer
|
|
7
|
+
* THE WORKFLOW OWNS ITS LEDGER ROW for its whole lifecycle — the one other writer is the API
|
|
8
|
+
* lane's inline run (`evaluateInline`, workflows/evaluate.ts), the same `evaluate` body run by the
|
|
9
|
+
* accepting request for a caller that waits; it takes the row only from `queued` (writing its lease,
|
|
10
|
+
* `inlineUntil`, in the same statement), and the steps below find what it wrote:
|
|
8
11
|
* step "record-queued" → upsert the `claim_ingests` row as `queued` (durable: the row exists
|
|
9
|
-
* iff the instance started, so nothing can ever strand a row)
|
|
10
|
-
*
|
|
12
|
+
* iff the instance started, so nothing can ever strand a row) — never
|
|
13
|
+
* over a row already `processing` / `processed`, which an inline run
|
|
14
|
+
* (or an earlier run of this instance) wrote and a rerun must not undo
|
|
15
|
+
* step "evaluate" → (workflows/evaluate.ts) a recorded decision is returned as is; else
|
|
16
|
+
* mark the row `processing` (so a later attempt knows one ran), then
|
|
11
17
|
* ONE pull (chain metadata + body + attachment descriptors), the facts
|
|
12
18
|
* lane over the same in-memory claim (`buildFacts`: read the engine's
|
|
13
19
|
* rubric manifest, run the producer, freeze the FactSet), and `POST /v1/decisions` on
|
|
@@ -28,7 +34,11 @@
|
|
|
28
34
|
* ingest — the decision is recorded, and an operator rerun re-enters
|
|
29
35
|
* delivery idempotently. A `pending_review` decision waits for the
|
|
30
36
|
* review lane (routes/v1/reviews.ts → ReviewComplete) to act instead
|
|
31
|
-
* step "mark-processed" → row → `processed`
|
|
37
|
+
* step "mark-processed" → row → `processed` — right after the decision (and the act), so the
|
|
38
|
+
* ledger reads `processed` beside it without waiting on a receiver;
|
|
39
|
+
* AFTER the notify for a `pending_review`, whose record reads its
|
|
40
|
+
* tasks off the `review_required` event the notify writes
|
|
41
|
+
* step "notify-review" → the source's notify lane (fail-soft, its own delivery ledger)
|
|
32
42
|
* terminal catch → row → `failed` (+ the message), instance shows Errored in the dashboard
|
|
33
43
|
* The cron (cron/) only discovers claims and creates instances; it never writes this table.
|
|
34
44
|
*
|
|
@@ -85,6 +95,7 @@
|
|
|
85
95
|
import { WorkflowEntrypoint, type WorkflowEvent, type WorkflowStep } from "cloudflare:workers";
|
|
86
96
|
import type { ClaimLaneKind } from "../contracts/index.js";
|
|
87
97
|
import type { OracleEnv } from "../env.js";
|
|
98
|
+
export { type EvaluateResult, GRANT_RETRY_DELAY, PAYER_BILLING } from "./evaluate.js";
|
|
88
99
|
export interface ClaimIngestParams {
|
|
89
100
|
claimId: string;
|
|
90
101
|
/** Known at cron discovery time; absent on manual runs (resolved on-chain in `record-queued`). */
|
|
@@ -104,28 +115,6 @@ export interface ClaimIngestParams {
|
|
|
104
115
|
/** The accepting request's id, API lane only. */
|
|
105
116
|
requestId?: string;
|
|
106
117
|
}
|
|
107
|
-
/** What leaves the evaluate step: small, log-safe, enough to reason about the run — never the facts. */
|
|
108
|
-
export interface EvaluateResult {
|
|
109
|
-
status: string;
|
|
110
|
-
verdict: string | null;
|
|
111
|
-
resultDigest: string | null;
|
|
112
|
-
receiptCid: string | null;
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* How a review-billing trouble is told apart in the ledger's `error` (a run that gave up while its
|
|
116
|
-
* collection was paused for payment): the resume cron restarts exactly those.
|
|
117
|
-
*/
|
|
118
|
-
export declare const PAYER_BILLING = "payer-billing:";
|
|
119
|
-
/**
|
|
120
|
-
* `403 NO_EVALUATE_GRANT` is retry-ONCE (docs/ENGINE-CONTRACT.md): the grant may have landed on
|
|
121
|
-
* chain seconds ago — the portal grants and registers in one flow — so wait about a block and ask
|
|
122
|
-
* again before calling it a real "not hired". In-step on purpose: the FactSet may not leave the
|
|
123
|
-
* step, so a step-level sleep would cost a full rebuild (connectors, AI charges). An object so a
|
|
124
|
-
* test can shorten it.
|
|
125
|
-
*/
|
|
126
|
-
export declare const GRANT_RETRY_DELAY: {
|
|
127
|
-
ms: number;
|
|
128
|
-
};
|
|
129
118
|
export declare class ClaimIngest extends WorkflowEntrypoint<OracleEnv, ClaimIngestParams> {
|
|
130
119
|
run(event: WorkflowEvent<ClaimIngestParams>, step: WorkflowStep): Promise<{
|
|
131
120
|
status: string;
|
|
@@ -136,104 +125,6 @@ export declare class ClaimIngest extends WorkflowEntrypoint<OracleEnv, ClaimInge
|
|
|
136
125
|
ok: boolean;
|
|
137
126
|
}>;
|
|
138
127
|
private ingest;
|
|
139
|
-
/**
|
|
140
|
-
* The evaluate step's body: pull → facts → decide → the `decisions` row. Reads the DB, not step
|
|
141
|
-
* results, so an operator rerun converges — and a retry that finds the row is done.
|
|
142
|
-
*/
|
|
143
|
-
private evaluate;
|
|
144
|
-
/**
|
|
145
|
-
* Who pays for this chain claim's review (header): null when its collection pays by its
|
|
146
|
-
* evaluation leg (or the oracle no longer bills per review); `reserved` when a charge already
|
|
147
|
-
* holds it (a retry); else the payer, resolved fresh — never a guess: the engine's or the chain's
|
|
148
|
-
* trouble retries the step, and no usable delegation pauses the collection `payer-delegation`.
|
|
149
|
-
*/
|
|
150
|
-
private billingFor;
|
|
151
|
-
/**
|
|
152
|
-
* A billing pause. The payer's two: the owner's notice, never a page (a customer's condition).
|
|
153
|
-
* `oracle-plan`: IXO's to fix — paged, no notice to the owner or the payer.
|
|
154
|
-
*/
|
|
155
|
-
private pausePayer;
|
|
156
|
-
/** The normal path: pull → build → (reserve) → decide → the `decisions` row. */
|
|
157
|
-
private decideFresh;
|
|
158
|
-
/** Reserve the review (payments/review-billing.ts), or say why not — a pause, a retry, a stop. */
|
|
159
|
-
private reserve;
|
|
160
|
-
/**
|
|
161
|
-
* A decision recovered from the engine's store → its `decisions` row.
|
|
162
|
-
*
|
|
163
|
-
* It is FINAL for this claim — the engine will not judge it twice — so it outranks anything this
|
|
164
|
-
* attempt would have concluded, including a build that failed. What it lacks is the facts it was
|
|
165
|
-
* decided on: the attempt that produced them died before writing the row, and the engine keeps a
|
|
166
|
-
* trace, not a FactSet. So they are rebuilt here — and stand in for the originals only if the
|
|
167
|
-
* rebuild is PROVABLY the same one, which is exactly what the engine's `factsDigest` proves.
|
|
168
|
-
* Anything else (a non-deterministic fact, a re-anchored rubric, a failed rebuild) is written as
|
|
169
|
-
* a park with its reason, at write time: better an explicit blocked row naming the drift than a
|
|
170
|
-
* decided row the act lane refuses later without knowing why.
|
|
171
|
-
*
|
|
172
|
-
* The rebuild may not even be ATTEMPTABLE: the owner's delegation can expire while the claim
|
|
173
|
-
* sits between attempts, and then the pull fail-closes 403. A deterministic "no" there is NOT a
|
|
174
|
-
* reason to lose the decision — the ingest would be marked `failed` with no row at all, while
|
|
175
|
-
* the engine holds a final answer it will never issue again. So it is recorded parked, facts
|
|
176
|
-
* null, and the act lane refuses to sign it (src/act.ts reads those facts). Only a transient
|
|
177
|
-
* failure is rethrown, so the step still retries and a later attempt can record the real facts.
|
|
178
|
-
*/
|
|
179
|
-
private recordRecovered;
|
|
180
|
-
/**
|
|
181
|
-
* The engine's answer → the `decisions` row, the collection's rubric pin and the `unusable`
|
|
182
|
-
* pause: ONE path whether the answer came from `POST /v1/decisions` just now or was recovered
|
|
183
|
-
* from the engine's store on a retry (see `evaluate`), so the two can never drift apart.
|
|
184
|
-
*
|
|
185
|
-
* `sent` is the FactSet this decision was made on — its `ext`/`ai` are frozen onto the row for
|
|
186
|
-
* the act policy to read at signing time (schema.ts `decisions.facts`), and nothing else of it
|
|
187
|
-
* is: `answers`/`attachments` are the claim's erasable surface and never persisted here. Null
|
|
188
|
-
* only on the recovery path when the rebuild could not be proven to be the same facts, which is
|
|
189
|
-
* what `park` says: the row is written `blocked` with that reason instead of `pending`, so the
|
|
190
|
-
* claim read explains itself and the act lane never has to guess.
|
|
191
|
-
*/
|
|
192
|
-
private record;
|
|
193
|
-
/**
|
|
194
|
-
* `api.decision.latency` — accept → decision row, the SLO metric. Accepted is the API claim's
|
|
195
|
-
* `receivedAt`, or the chain claim's ledger `createdAt` (its first `record-queued`). `status` says
|
|
196
|
-
* whether the protocol's rubric runs AI checks: the frozen FactSet's `ai` keys are exactly the
|
|
197
|
-
* work order's (validate.ts holds them to the manifest), so no extra read; `-` only when a
|
|
198
|
-
* recovered decision's facts could not be rebuilt. Best-effort: a metric never fails the step.
|
|
199
|
-
*/
|
|
200
|
-
private decisionLatency;
|
|
201
|
-
/**
|
|
202
|
-
* `POST /v1/decisions`, with the one recoverable refusal handled here: `RUBRIC_PIN_MISMATCH` —
|
|
203
|
-
* our pin ≠ the chain's `#rub` proof as the engine read it, i.e. `#rub` was re-anchored between
|
|
204
|
-
* our (KV-cached) manifest read and theirs. Invalidate and re-read the manifest ONCE: a changed
|
|
205
|
-
* pin is a new work order (new facts, so a rebuild — connectors run again; the fact cache is
|
|
206
|
-
* keyed by the pin, fact-cache.ts), the same pin means the engine and the chain disagree, which
|
|
207
|
-
* no retry of ours fixes. The manifest may also have turned `unusable` under the new anchor —
|
|
208
|
-
* then the rebuild records that, and never decides.
|
|
209
|
-
*/
|
|
210
|
-
private decide;
|
|
211
|
-
/** One decide call, with the contract's retry-once on `NO_EVALUATE_GRANT` (see `GRANT_RETRY_DELAY`). */
|
|
212
|
-
private ask;
|
|
213
|
-
/**
|
|
214
|
-
* The engine said no (docs/ENGINE-CONTRACT.md "Errors"): do what the table says, then hand back
|
|
215
|
-
* the error to throw — NonRetryable for a deterministic refusal, the original for a retryable
|
|
216
|
-
* one. Non-engine errors pass through for `stepError` to classify.
|
|
217
|
-
*/
|
|
218
|
-
private engineFailure;
|
|
219
|
-
/**
|
|
220
|
-
* Facts that don't match the rubric's work order (lib/facts/validate.ts) — the producer's bug,
|
|
221
|
-
* never a claim outcome: the issue list is codes and paths (identifiers), logged and paged so the
|
|
222
|
-
* fix is one grep away, and the error to throw is NonRetryable (a retry would re-run the same
|
|
223
|
-
* producer). The row is already recorded by the caller.
|
|
224
|
-
*/
|
|
225
|
-
private invalidFacts;
|
|
226
|
-
/**
|
|
227
|
-
* A claim the facts lane could not build for — recorded WITHOUT a decide call (schema.ts
|
|
228
|
-
* `decisions`): `status` names the reason, `explanation` the issues, and nothing will ever be
|
|
229
|
-
* acted on, so `chainStatus` is `skipped` from the start. Then the reason's consequence:
|
|
230
|
-
* `rubric-unusable` is the engine's manifest saying the rubric cannot be bound — the same
|
|
231
|
-
* handling as its decide-time `unusable` (pause the collection; steps.ts), minus the receipt, and
|
|
232
|
-
* the ingest completes; `invalid-facts` is OUR (or the provider's) bug, never a claim outcome —
|
|
233
|
-
* recorded so the claim read says why, then failed loudly, like the engine's own `VALIDATION`
|
|
234
|
-
* refusal this check exists to catch first.
|
|
235
|
-
*/
|
|
236
|
-
private buildFailure;
|
|
237
128
|
/**
|
|
238
129
|
* A terminal failure's class — the API lane's §5 code (lib/api-lane/record.ts `claimErrorCode`,
|
|
239
130
|
* read off the same message the ledger stores), for either lane. Best-effort like the rest of
|
|
@@ -243,7 +134,10 @@ export declare class ClaimIngest extends WorkflowEntrypoint<OracleEnv, ClaimInge
|
|
|
243
134
|
private ledgerRow;
|
|
244
135
|
/**
|
|
245
136
|
* Upsert this claim's ledger row. `error` is null unless `failed` (schema.ts), so a rerun that
|
|
246
|
-
* succeeds clears the old message.
|
|
137
|
+
* succeeds clears the old message. `queued` never lands on a row already `processing` or
|
|
138
|
+
* `processed`: the inline run (or an earlier run of this instance) got that far, and moving it
|
|
139
|
+
* back would hide an inline run in flight from `evaluate` (two runs, the handlers paid twice) and
|
|
140
|
+
* show a decided claim as `queued` until the run caught up.
|
|
247
141
|
*/
|
|
248
142
|
private recordStatus;
|
|
249
143
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claim-ingest.d.ts","sourceRoot":"","sources":["../../src/workflows/claim-ingest.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"claim-ingest.d.ts","sourceRoot":"","sources":["../../src/workflows/claim-ingest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6FG;AAEH,OAAO,EAAE,kBAAkB,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAI/F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAGlD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAaxC,OAAO,EAAE,KAAK,cAAc,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEnF,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,kGAAkG;IAClG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAUD,qBAAa,WAAY,SAAQ,kBAAkB,CAAC,SAAS,EAAE,iBAAiB,CAAC;IAChE,GAAG,CAAC,KAAK,EAAE,aAAa,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,YAAY;;;;;;;OAsB7E;YAEa,MAAM;IA0LpB;;;;OAIG;YACW,YAAY;IAa1B,OAAO,CAAC,SAAS;IAMjB;;;;;;OAMG;YACW,YAAY;CA+B3B"}
|