@engramx/idl 0.16.0-rc.1

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.
@@ -0,0 +1,1354 @@
1
+ import type { Principal } from '@icp-sdk/core/principal';
2
+ import type { ActorMethod } from '@icp-sdk/core/agent';
3
+ import type { IDL } from '@icp-sdk/core/candid';
4
+
5
+ export interface AccessGrant {
6
+ expiresAt: bigint;
7
+ contentRef: ContentRef;
8
+ hmac: Uint8Array | number[];
9
+ grantId: string;
10
+ grantee: Principal;
11
+ receiptId: string;
12
+ issuedAt: bigint;
13
+ }
14
+ export interface AdminRoles {
15
+ roles: Array<RoleGrant>;
16
+ }
17
+ export interface AuditEntry {
18
+ id: bigint;
19
+ entryHash: Uint8Array | number[];
20
+ callerRole: Role;
21
+ operation: string;
22
+ details: string;
23
+ caller: Principal;
24
+ success: boolean;
25
+ timestampNs: bigint;
26
+ }
27
+ export interface AuditHead {
28
+ headHash: Uint8Array | number[];
29
+ size: bigint;
30
+ }
31
+ export interface CertifiedAuditHead {
32
+ total: bigint;
33
+ certificate: [] | [Uint8Array | number[]];
34
+ headHash: Uint8Array | number[];
35
+ size: bigint;
36
+ witness: [] | [Uint8Array | number[]];
37
+ }
38
+ export interface ContentDelivery {
39
+ settlementTxHash: [] | [string];
40
+ grant: AccessGrant;
41
+ delivery: DeliveryMethod;
42
+ }
43
+ export interface ContentEntry {
44
+ id: string;
45
+ createdAt: bigint;
46
+ mimeType: string;
47
+ totalSize: bigint;
48
+ chunkCount: bigint;
49
+ }
50
+ export interface ContentRef {
51
+ id: string;
52
+ metadata: [] | [Array<[string, string]>];
53
+ mimeType: [] | [string];
54
+ sizeBytes: [] | [bigint];
55
+ }
56
+ export type ContentResponse =
57
+ { Delivered: ContentDelivery } | { PaymentRequired: Array<PaymentRequirement> };
58
+ export type DeliveryMethod =
59
+ | { httpUrl: string }
60
+ | { inline: Uint8Array | number[] }
61
+ | { canisterQuery: { method: string; chunkCount: bigint } }
62
+ | { assetCanister: { path: string; canisterId: Principal } };
63
+ export interface Eip3009Authorization {
64
+ r: Uint8Array | number[];
65
+ s: Uint8Array | number[];
66
+ v: number;
67
+ to: string;
68
+ value: bigint;
69
+ from: string;
70
+ validAfter: bigint;
71
+ nonce: Uint8Array | number[];
72
+ validBefore: bigint;
73
+ }
74
+ export type EndpointStatus = { Enabled: null } | { Disabled: null } | { Deleted: null };
75
+ export type Error =
76
+ | { Invalid: string }
77
+ | { NotFound: string }
78
+ | { Refused: string }
79
+ | { Other: string }
80
+ | { Unavailable: string }
81
+ | { Conflict: string };
82
+ export interface GenesisNote {
83
+ predecessorSize: [] | [bigint];
84
+ predecessorHeadHash: [] | [Uint8Array | number[]];
85
+ note: string;
86
+ version: string;
87
+ genesisAtNs: bigint;
88
+ }
89
+ export interface HttpRequest {
90
+ url: string;
91
+ method: string;
92
+ body: Uint8Array | number[];
93
+ headers: Array<[string, string]>;
94
+ }
95
+ export interface HttpResponse {
96
+ body: Uint8Array | number[];
97
+ headers: Array<[string, string]>;
98
+ upgrade: [] | [boolean];
99
+ status_code: number;
100
+ }
101
+ export interface Job {
102
+ id: string;
103
+ completedAtNs: [] | [bigint];
104
+ expiresAtNs: bigint;
105
+ status: JobStatus;
106
+ result: [] | [Uint8Array | number[]];
107
+ paymentReceiptId: string;
108
+ deliveryCallback: [] | [string];
109
+ parkedTx: [] | [ParkedTx];
110
+ operator: [] | [Principal];
111
+ createdAtNs: bigint;
112
+ actualCost: [] | [bigint];
113
+ buyer: string;
114
+ serviceId: string;
115
+ proof: [] | [Uint8Array | number[]];
116
+ amount: bigint;
117
+ params: Uint8Array | number[];
118
+ }
119
+ export interface JobCounts {
120
+ total: bigint;
121
+ active: bigint;
122
+ expired: bigint;
123
+ settled: bigint;
124
+ refunded: bigint;
125
+ settling: bigint;
126
+ parked: bigint;
127
+ }
128
+ export type JobStatus =
129
+ | { Disputed: null }
130
+ | { Refunded: null }
131
+ | { Computing: null }
132
+ | { other: string }
133
+ | { Settling: null }
134
+ | { Submitted: null }
135
+ | { Assigned: null }
136
+ | { Verified: null }
137
+ | { Expired: null }
138
+ | { Settled: null }
139
+ | { Pending: null };
140
+ export interface Page {
141
+ total: bigint;
142
+ withheld: bigint;
143
+ items: Array<ServiceDefinition>;
144
+ }
145
+ export interface Page_1 {
146
+ total: bigint;
147
+ withheld: bigint;
148
+ items: Array<PendingWithdrawal>;
149
+ }
150
+ export interface Page_2 {
151
+ total: bigint;
152
+ withheld: bigint;
153
+ items: Array<Job>;
154
+ }
155
+ export interface Page_3 {
156
+ total: bigint;
157
+ withheld: bigint;
158
+ items: Array<X402Endpoint>;
159
+ }
160
+ export interface Page_4 {
161
+ total: bigint;
162
+ withheld: bigint;
163
+ items: Array<PurchaseRecord>;
164
+ }
165
+ export interface Page_5 {
166
+ total: bigint;
167
+ withheld: bigint;
168
+ items: Array<AuditEntry>;
169
+ }
170
+ export interface Page_6 {
171
+ total: bigint;
172
+ withheld: bigint;
173
+ items: Array<ContentEntry>;
174
+ }
175
+ export interface Page_7 {
176
+ total: bigint;
177
+ withheld: bigint;
178
+ items: Array<Principal>;
179
+ }
180
+ export type ParkedLeg = { UptoRemainder: null } | { Refund: null } | { Settle: null };
181
+ export interface ParkedTx {
182
+ leg: ParkedLeg;
183
+ token: string;
184
+ parkedAt: bigint;
185
+ txHash: string;
186
+ chainId: bigint;
187
+ }
188
+ export type Payer = { Evm: string } | { Icp: Principal };
189
+ export interface PaymentQuote {
190
+ amountE6: bigint;
191
+ requirements: Array<QuotedRequirement>;
192
+ }
193
+ export interface PaymentRequirement {
194
+ token: string;
195
+ tokenVersion: [] | [string];
196
+ scheme: string;
197
+ recipient: string;
198
+ network: string;
199
+ nonce: Uint8Array | number[];
200
+ tokenName: [] | [string];
201
+ expiry: bigint;
202
+ amount: bigint;
203
+ }
204
+ export interface PaymentSignature {
205
+ signature: Uint8Array | number[];
206
+ asset: [] | [string];
207
+ publicKey: [] | [Uint8Array | number[]];
208
+ scheme: string;
209
+ network: string;
210
+ sender: string;
211
+ nonce: Uint8Array | number[];
212
+ authorization: [] | [Eip3009Authorization];
213
+ }
214
+ export interface PendingWithdrawal {
215
+ id: bigint;
216
+ parkedAtNs: bigint;
217
+ createdAtTimeNs: bigint;
218
+ seller: Principal;
219
+ amountE6s: bigint;
220
+ reason: string;
221
+ }
222
+ export type PricingScheme = { Exact: bigint } | { Upto: bigint } | { Session: null };
223
+ export interface PurchaseRecord {
224
+ id: string;
225
+ endpointId: string;
226
+ network: string;
227
+ txHash: [] | [string];
228
+ receiptId: string;
229
+ buyer: Payer;
230
+ amount: bigint;
231
+ timestampNs: bigint;
232
+ }
233
+ export interface QuotedRequirement {
234
+ token: string;
235
+ tokenVersion: [] | [string];
236
+ scheme: string;
237
+ recipient: string;
238
+ network: string;
239
+ expiryNs: bigint;
240
+ tokenName: [] | [string];
241
+ amount: bigint;
242
+ }
243
+ export type Result = { Ok: bigint } | { Err: Error };
244
+ export type Result_1 = { Ok: null } | { Err: Error };
245
+ export type Result_10 = { Ok: SellerStatus } | { Err: Error };
246
+ export type Result_11 = { Ok: RevenueSummary } | { Err: Error };
247
+ export type Result_12 = { Ok: JobStatus } | { Err: Error };
248
+ export type Result_13 = { Ok: Uint8Array | number[] } | { Err: Error };
249
+ export type Result_14 = { Ok: Job } | { Err: Error };
250
+ export type Result_15 = { Ok: [] | [string] } | { Err: Error };
251
+ export type Result_16 = { Ok: ContentResponse } | { Err: Error };
252
+ export type Result_17 = { Ok: ServiceRequestResponse } | { Err: Error };
253
+ export type Result_18 = { Ok: X402Endpoint } | { Err: Error };
254
+ export type Result_2 = { Ok: string } | { Err: Error };
255
+ export type Result_3 = { Ok: PaymentQuote } | { Err: Error };
256
+ export type Result_4 = { Ok: SessionState } | { Err: Error };
257
+ export type Result_5 = { Ok: Page_1 } | { Err: Error };
258
+ export type Result_6 = { Ok: Page_2 } | { Err: Error };
259
+ export type Result_7 = { Ok: Page_4 } | { Err: Error };
260
+ export type Result_8 = { Ok: Page_5 } | { Err: Error };
261
+ export type Result_9 = { Ok: Page_7 } | { Err: Error };
262
+ export interface RevenueSummary {
263
+ serviceJobsSettled: bigint;
264
+ owedToYou: bigint;
265
+ endpointBreakdown: Array<{
266
+ revenue: bigint;
267
+ endpointId: string;
268
+ name: string;
269
+ purchases: bigint;
270
+ }>;
271
+ contentRevenue: bigint;
272
+ serviceRevenue: bigint;
273
+ contentPurchases: bigint;
274
+ unresolvedWithdrawals: bigint;
275
+ }
276
+ export type Role =
277
+ | { Anonymous: null }
278
+ | { Viewer: null }
279
+ | { Engram: null }
280
+ | { Root: null }
281
+ | { Buyer: null }
282
+ | { WasmAdmin: null }
283
+ | { Guardian: null }
284
+ | { Seller: null }
285
+ | { Admin: null }
286
+ | { Agent: null }
287
+ | { Other: null }
288
+ | { Owner: null };
289
+ export interface RoleGrant {
290
+ role: { Root: null } | { WasmAdmin: null } | { Admin: null } | { Other: string };
291
+ holder: Principal;
292
+ }
293
+ export interface SellerStatus {
294
+ expiresAtNs: bigint;
295
+ verifiedAtNs: bigint;
296
+ bytesStored: bigint;
297
+ engramId: Principal;
298
+ byteQuota: bigint;
299
+ }
300
+ export interface ServiceDefinition {
301
+ id: string;
302
+ serviceType: ServiceType;
303
+ name: string;
304
+ createdAt: bigint;
305
+ description: string;
306
+ pricing: PricingScheme;
307
+ enabled: boolean;
308
+ operatorId: Principal;
309
+ delivery: ServiceDeliveryMethod;
310
+ timeout: bigint;
311
+ verification: VerificationMethod;
312
+ }
313
+ export type ServiceDeliveryMethod = { Both: null } | { Poll: null } | { Callback: null };
314
+ export type ServiceRequestResponse =
315
+ { Accepted: { jobId: string } } | { PaymentRequired: Array<PaymentRequirement> };
316
+ export type ServiceType = { Sync: null } | { Async: null };
317
+ export interface SessionConfig {
318
+ autoClose: boolean;
319
+ idleTimeout: [] | [bigint];
320
+ maxDeposit: bigint;
321
+ }
322
+ export interface SessionCounts {
323
+ closed: bigint;
324
+ total: bigint;
325
+ expired: bigint;
326
+ open: bigint;
327
+ closing: bigint;
328
+ }
329
+ export interface SessionIntent {
330
+ token: string;
331
+ costPerCall: [] | [bigint];
332
+ minDeposit: [] | [bigint];
333
+ recipient: string;
334
+ network: string;
335
+ description: [] | [string];
336
+ expiryNs: bigint;
337
+ suggestedDeposit: bigint;
338
+ }
339
+ export interface SessionState {
340
+ id: string;
341
+ status: SessionStatus;
342
+ deposited: bigint;
343
+ openedAtNs: bigint;
344
+ lastActivityAtNs: bigint;
345
+ consumed: bigint;
346
+ voucherCount: bigint;
347
+ remaining: bigint;
348
+ payer: Payer;
349
+ }
350
+ export type SessionStatus =
351
+ { closed: null } | { expired: null } | { other: string } | { open: null } | { closing: null };
352
+ export interface SpendingPolicy {
353
+ maxSessionDeposit: [] | [bigint];
354
+ blockedCallers: [] | [Array<Principal>];
355
+ maxPerDay: [] | [bigint];
356
+ maxSessionDuration: [] | [bigint];
357
+ sessionIdleTimeout: [] | [bigint];
358
+ rateLimitPerMinute: [] | [bigint];
359
+ maxPerTransaction: [] | [bigint];
360
+ allowedCallers: [] | [Array<Principal>];
361
+ maxConcurrentSessions: [] | [bigint];
362
+ }
363
+ export type TokenAmount = { Icp: bigint } | { Ckusdc: bigint } | { Ckusdt: bigint };
364
+ export type VerificationMethod =
365
+ | {
366
+ BuyerConfirm: { disputeWindowSeconds: bigint };
367
+ }
368
+ | {
369
+ ZkGroth16: {
370
+ bindResult: boolean;
371
+ verifierCanister: Principal;
372
+ verificationKey: Uint8Array | number[];
373
+ };
374
+ }
375
+ | { AutoSettle: null }
376
+ | { HashMatch: null };
377
+ export interface X402Endpoint {
378
+ id: string;
379
+ status: EndpointStatus;
380
+ contentId: [] | [string];
381
+ enabledBy: [] | [Principal];
382
+ name: string;
383
+ createdBy: Principal;
384
+ createdAtNs: bigint;
385
+ description: string;
386
+ totalPurchases: bigint;
387
+ totalRevenue: bigint;
388
+ price: bigint;
389
+ suggestedPrice: bigint;
390
+ enabledAtNs: [] | [bigint];
391
+ }
392
+ export interface _SERVICE {
393
+ addAuditViewer: ActorMethod<[Principal], Result_1>;
394
+ /**
395
+ * / Push this canister's chain head into the registry's anchor ring — the same thing every engram
396
+ * / does with its memory head, and the cashier with its treasury head.
397
+ * /
398
+ * / L12's argument applies to escrow with full force: a self-attested commerce ledger sitting
399
+ * / beside witnessed ones is the asymmetry an auditor finds first. Every chain in this system is
400
+ * / witnessed by a party that does not control it, or the phrase means nothing.
401
+ * /
402
+ * / Best-effort and isolated: a registry that is slow or down must never take the market with it.
403
+ * / The FAILURE IS RECORDED rather than swallowed — an anchor push that silently stopped would
404
+ * / leave the chain looking witnessed while it was not, which is worse than a visibly missing one.
405
+ * /
406
+ * / ⟨RENAMED 2026-10-02 from `sysAnchorNow`, with `setRegistryId` and for the same reason: its
407
+ * / caller is the market's admin, a person, so it does not belong to the canister-to-canister
408
+ * / tier the `sys` prefix names.⟩
409
+ */
410
+ anchorNow: ActorMethod<[], Result_1>;
411
+ /**
412
+ * / A seller takes on a pending job. The CALLER must be the seller of the service the job was
413
+ * / created against — claiming is not open, and there is no assignment step: whoever registered
414
+ * / the service claims its work.
415
+ * /
416
+ * / ⚠ EVERY FAILURE ARRIVES AS `#Conflict`, INCLUDING ONES THAT ARE NOT CONFLICTS. The refusals
417
+ * / come from the vendored ic402 service registry as plain strings, so the arm is already lost
418
+ * / when this method sees them. `#Conflict` here therefore covers FOUR distinct situations:
419
+ * / · the job does not exist ⟶ properly `#NotFound`
420
+ * / · the service does not exist ⟶ properly `#NotFound`
421
+ * / · the job is not pending ⟶ properly `#Conflict`
422
+ * / · **you are not the seller** ⟶ properly `#Refused`
423
+ * /
424
+ * / **Read the MESSAGE, not the arm, on this method only.** That is the opposite of what L1 asks
425
+ * / everywhere else, and it is stated here rather than left to be discovered: a caller branching
426
+ * / on the arm will retry a call that can never succeed for it. Recovering the distinction needs
427
+ * / the LIBRARY to carry arms — matching its prose here would reintroduce exactly the
428
+ * / message-branching L1 abolished, and would break silently on an ic402 bump. ⟨Recorded with
429
+ * / three costed options in the project's backlog, 2026-08-21. This is the market's whole ic402
430
+ * / seam, not one method: 6 call sites collapse a module error into `#Conflict`.⟩
431
+ * / ⟨2026-10-02 — counted again, and ruled.⟩ ELEVEN sites on this market collapse an ic402 text
432
+ * / into `#Conflict`, not 6: `setServiceEnabled`, `claimJob`, `submitJobResult`, `confirmJob`,
433
+ * / `disputeJob`, `resolveDispute`, `reconcileSession`, `forceResolveSession`, `recoverEscrow`,
434
+ * / `reconcileJob`, `resolveJob` — each now carries its own audited caveat. Four can carry a
435
+ * / refusal of the caller's standing — `claimJob`, `confirmJob`, `disputeJob` and `submitJobResult`;
436
+ * / `setServiceEnabled`, the fourth noted on 2026-08-21, is now gated by this canister before the
437
+ * / library is called; the other six are state behind this canister's own gate. Read-the-message
438
+ * / is RATIFIED as the 0.16.0 contract (the owner's ruling of 2026-10-02, the pre-cut
439
+ * / recommendation); giving the library one arm per kind of refusal is post-cut dependency work,
440
+ * / not a change made mid-cut.
441
+ * /
442
+ * / It also refuses while TRADE IS FROZEN, and that one is a true `#Conflict` — the refusal says
443
+ * / so explicitly ("Not a permission problem and not a missing job"), and `isTradeFrozen()` is the
444
+ * / ungated read that confirms it.
445
+ */
446
+ claimJob: ActorMethod<[string], Result_1>;
447
+ /**
448
+ * / ⟨0.16.0, L2.6⟩ `confirmJob` ABSORBS `confirmJobEvm`. One buyer action, two ways to prove you
449
+ * / are the buyer.
450
+ * /
451
+ * / The pair existed because authorization arrives differently on the two rails, not because the
452
+ * / ACT differs: both release escrow to the seller. An ICP-rail buyer proves identity by calling
453
+ * / as their principal; an EVM-rail buyer has no principal here at all, so they prove it with a
454
+ * / secp256k1 signature over `getBuyerActionMessage`, which ic402 ecRecovers and compares to the job's
455
+ * / stored 0x buyer. `evmProof = null` means "authorize me as the caller".
456
+ * /
457
+ * / THE HARDENING IS ON THE SIGNATURE BRANCH ONLY, and deliberately so. That branch is
458
+ * / ANONYMOUS and does real work — an ecRecover plus, on success, an on-chain settle — so it is
459
+ * / griefable by anyone: it keeps the cycles floor (protect the canister's balance from drain) and
460
+ * / the per-caller rate limit. Applying the same rate limit to the principal branch would throttle
461
+ * / identified buyers to defend against a threat that branch does not have.
462
+ * /
463
+ * / ⚠ `#Conflict` HERE ALSO COVERS "NOT THE BUYER", which is a refusal and not a conflict. The
464
+ * / underlying ic402 registry returns plain strings, so the arm is gone before this method sees
465
+ * / it: `Job not found` (properly `#NotFound`), `Job not in submitted status` (properly
466
+ * / `#Conflict`) and **`Not the buyer`** (properly `#Refused`) all arrive as `#Conflict`. On THIS
467
+ * / method read the MESSAGE rather than the arm — it is terminal money settlement, so a caller
468
+ * / who reads `#Conflict` as "retry later" will retry a release that can never happen for them.
469
+ * / Same seam as `claimJob`; three costed fixes in the project's backlog ⟨2026-08-21⟩.
470
+ */
471
+ confirmJob: ActorMethod<[string, [] | [Uint8Array | number[]]], Result_1>;
472
+ /**
473
+ * / Create a content endpoint — a shelf in the storefront. Born DISABLED.
474
+ * /
475
+ * / Born disabled deliberately: a listing that went live at creation would be sellable before its
476
+ * / price was set, and `price` starts at 0 with `suggestedPrice` as the fallback.
477
+ */
478
+ createEndpoint: ActorMethod<[string, string, string, bigint], Result_18>;
479
+ /**
480
+ * / Submit a paid service request. Returns a job id, or the price.
481
+ * /
482
+ * / ⟨0.16.0⟩ TWO GATES FROM THE ENGRAM DO NOT TRAVEL, and both for the same reason: they were the
483
+ * / engram protecting ITS OWNER'S money, which is custody, and custody stayed.
484
+ * /
485
+ * / · `requireAgentOrOwner` — the engram only let its own agents spend its funds. Here the
486
+ * / caller is a BUYER paying with their own signature; gating that to a roster would mean a
487
+ * / marketplace only its own staff could buy from.
488
+ * / · `approvalId` / `#approvalPending` — an approval is the buyer's own spend policy, checked on
489
+ * / their engram before they call. Two arms and a parameter disappear because the
490
+ * / responsibility moved, not because a check was dropped.
491
+ * /
492
+ * / What DOES gate here is the market's freeze, and the service's own existence and pricing mode.
493
+ */
494
+ createJob: ActorMethod<[string, Uint8Array | number[], [] | [PaymentSignature]], Result_17>;
495
+ /**
496
+ * / Delete content.
497
+ * /
498
+ * / ⚠ THE QUOTA IS NOT REFUNDED, and this is the honest part of the design rather than a
499
+ * / meanness. The memory is not returned to the subnet when the entry goes — enhanced orthogonal
500
+ * / persistence never shrinks — so crediting the bytes back would let one seller cycle uploads
501
+ * / forever against a ceiling that only ever rose in reality. The quota tracks bytes CLAIMED, not
502
+ * / bytes currently held, because claimed is the number that costs money.
503
+ */
504
+ deleteContent: ActorMethod<[string], Result_1>;
505
+ /**
506
+ * / Delete an endpoint. Terminal — the record stays as #Deleted so purchase history keeps
507
+ * / resolving, and the id is never reused.
508
+ */
509
+ deleteEndpoint: ActorMethod<[string], Result_1>;
510
+ /**
511
+ * / ⟨0.16.0, L2.6⟩ `disputeJob` ABSORBS `disputeJobEvm`, exactly as confirmJob does, and for the
512
+ * / same reason: one act, two proofs of buyership.
513
+ * /
514
+ * / NOT FREEZE-GATED, and that asymmetry with confirmJob is deliberate. Recording a dispute moves
515
+ * / no money — it marks the job #Disputed, and any refund happens later through resolveDispute or
516
+ * / a timeout. A buyer must be able to say "this is wrong" DURING an emergency freeze; a freeze
517
+ * / that silenced complaints would protect the market from its own buyers.
518
+ * /
519
+ * / ⚠ `#Conflict` HERE ALSO COVERS "NOT THE BUYER" — same ic402 seam as `confirmJob` and
520
+ * / `claimJob`: `Job not found`, `Job not in submitted status` and **`Not the buyer`** all arrive
521
+ * / as `#Conflict` because the library hands back strings. Read the MESSAGE, not the arm.
522
+ * / ⟨2026-08-21; the project's backlog carries the three fixes and why none is a one-liner.⟩
523
+ * /
524
+ * / ⚠ AND NOTE WHERE THE DISPUTE GOES: `resolveDispute` is answered by the SERVICE'S OWN SELLER
525
+ * / — the party being disputed. This market has no admin arbitration and no appeal, deliberately
526
+ * / and on the record. Filing a dispute is not an escalation to a neutral party.
527
+ */
528
+ disputeJob: ActorMethod<[string, string, [] | [Uint8Array | number[]]], Result_1>;
529
+ /**
530
+ * / Closing refunds the unconsumed deposit to the payer, so it is NOT freeze-gated — the same
531
+ * / reasoning as disputeJob and forceCloseSession. A halt stops money moving toward sellers; it
532
+ * / must not strand a buyer's own escrow.
533
+ */
534
+ endSession: ActorMethod<[string], Result_1>;
535
+ /**
536
+ * / Admin recovery: force a stuck session closed and return the unconsumed deposit to its payer.
537
+ * /
538
+ * / Documented in RECOVERY-RUNBOOK as an owner procedure; on a shared canister the equivalent
539
+ * / authority is the market admin, because the session's own parties are precisely who cannot
540
+ * / unstick it. No discretion: the refund destination is the payer recorded on the session.
541
+ */
542
+ forceCloseSession: ActorMethod<[string], Result_1>;
543
+ /**
544
+ * / Admin recovery: mark a stuck session resolved. STATE ONLY — no funds move.
545
+ * /
546
+ * / Kept distinct from forceCloseSession, which refunds, because the two are different admissions.
547
+ * / This one says "the accounting is already right and the record is wrong"; that one says "return
548
+ * / what is left". Merging them would let a state repair silently move money.
549
+ * /
550
+ * / NOT freeze-gated, and the asymmetry is the point: a freeze halts SETTLEMENT, and this settles
551
+ * / nothing. An admin must be able to repair a record during the halt that made the record wrong.
552
+ * /
553
+ * / ⟨2026-10-02, the payment library's refusal channel — audited at this site⟩ `#Conflict` here
554
+ * / carries ic402's text, and ic402 answers with one text channel for every refusal. AUDITED:
555
+ * / this method's own gate (`requireAdmin`) decides authorization before the library is called, and every
556
+ * / text the library returns here is a STATE refusal (session missing, or not stuck in #closing) — including "not found", which
557
+ * / arrives as `#Conflict` rather than `#NotFound`. Read the MESSAGE for which. This is the 0.16.0
558
+ * / contract as ratified on 2026-10-02; giving the library one arm per kind of refusal is post-cut
559
+ * / dependency work.
560
+ */
561
+ forceResolveSession: ActorMethod<[string], Result_1>;
562
+ /**
563
+ * / PUBLIC: accountability requires knowing who holds power. This is the shape every canister
564
+ * / in the system serves, so one reader covers all of them.
565
+ */
566
+ getAdminRoles: ActorMethod<[], AdminRoles>;
567
+ /**
568
+ * / PUBLIC: a head exists to be compared. A head nobody can read witnesses nothing.
569
+ */
570
+ getAuditHead: ActorMethod<[], AuditHead>;
571
+ /**
572
+ * / The exact message an EVM buyer signs (keccak256 of it) to confirm or dispute a job.
573
+ * /
574
+ * / PUBLIC: it must be, since the caller who needs it is by definition unauthenticated here.
575
+ * / It binds action + job + THIS canister, so a signature cannot be replayed across actions, across
576
+ * / jobs, or onto another market.
577
+ */
578
+ getBuyerActionMessage: ActorMethod<[string, string], string>;
579
+ /**
580
+ * / PUBLIC: the subnet-certified head, so a client verifies against the NNS root rather than
581
+ * / trusting this replica. `witness` is null until this canister grows a certified tree — an
582
+ * / honest absence, distinct from an empty proof.
583
+ */
584
+ getCertifiedAuditHead: ActorMethod<[], CertifiedAuditHead>;
585
+ /**
586
+ * / Paid content read. `#PaymentRequired` comes back inside `#Ok` — see Types.ContentResponse for
587
+ * / why a price is an answer rather than an error.
588
+ * /
589
+ * / The `approvalId` parameter is gone, as it is on openSession: an approval is the BUYER's own
590
+ * / custody policy, checked on their engram before they call here.
591
+ * /
592
+ * / ⟨L7⟩ UPDATE, NOT QUERY: the paid path awaits `gate.settle(sig, ?amount)`, an inter-canister
593
+ * / settlement. A query cannot await it, and splitting the free and paid halves into two methods
594
+ * / would put the price and the content behind different names for one buyer act.
595
+ * /
596
+ * / ⟨2026-09-30, ic402 2.17.0⟩ It now awaits `gate.settleFrom(msg.caller, sig, ?amount)`. On the
597
+ * / ICP rail a signature's `sender` is only a claim — the payer's ICRC-2 allowance is the whole
598
+ * / authentication — so `settle` would spend the allowance of whoever the signature named and
599
+ * / deliver the content to the caller. `settleFrom` refuses unless the caller IS the named sender,
600
+ * / before the nonce lock or any ledger call, and the refusal reaches the buyer as #Refused with
601
+ * / ic402's text naming both principals. Pay as the principal that approved the allowance.
602
+ */
603
+ getContent: ActorMethod<[string, [] | [PaymentSignature]], Result_16>;
604
+ /**
605
+ * / ⟨0.16.0⟩ THE `getChunk` FIX, and it is the sharpest single case in the corpus.
606
+ * /
607
+ * / The engram's version was:
608
+ * /
609
+ * / switch (gate.verifyGrant(msg.caller, grant)) {
610
+ * / case (#ok) { contentStore.getChunk(grant.contentRef.id, index) };
611
+ * / case (_) { null };
612
+ * / };
613
+ * /
614
+ * / `AccessGrantResult` has FOUR arms — `#ok`, `#expired`, `#invalidGrant`, `#revoked` — each
615
+ * / carrying its own explanatory text. All three failures were collapsed into `null`, which is
616
+ * / ALSO what the content store returns for "that chunk index does not exist". So a buyer whose
617
+ * / grant had expired, a buyer whose grant was revoked, and a buyer asking for a chunk past the end
618
+ * / of a file received byte-identical answers. The information existed — the sibling `verifyGrant`
619
+ * / returned the full result — and was discarded one line later.
620
+ * /
621
+ * / Worse than uninformative: a buyer who PAID and whose grant expired sees "no such chunk" and
622
+ * / concludes the content is gone, not that their access lapsed. On a paid rail that is a refund
623
+ * / request and a support ticket generated by a type.
624
+ * /
625
+ * / The honesty gates could not see it. `gate.verifyGrant` is a PAYMENT gate, and the gate-call
626
+ * / list they scan holds authorization helpers only — so a refusal fabricated behind a payment
627
+ * / check was out of scope by construction rather than by ruling. L11 adds payment gates to that
628
+ * / list; this method is why.
629
+ */
630
+ getContentChunk: ActorMethod<[AccessGrant, bigint], Result_13>;
631
+ /**
632
+ * / A seller's payout address — THEIRS, or the admin's to read.
633
+ * /
634
+ * / The engram made this owner-only and TRAPPED at everyone else. Here the answer is a refusal a
635
+ * / caller can read, and `#Ok(null)` genuinely means "this seller has set no payout address" —
636
+ * / distinguishable from "you may not ask", which is the whole point of the envelope.
637
+ */
638
+ getEvmSellerPayout: ActorMethod<[Principal], Result_15>;
639
+ /**
640
+ * / PUBLIC: what this canister's chains continue, or that they continue nothing. A fresh chain
641
+ * / beside a published predecessor head is auditable; a fresh chain with no statement is
642
+ * / indistinguishable from a wipe.
643
+ */
644
+ getGenesisNote: ActorMethod<[], GenesisNote>;
645
+ /**
646
+ * / ⟨0.16.0, L1⟩ The engram TRAPPED here. Trapping was the right fix at the time — it stopped the
647
+ * / refusal masquerading as a not-found — but it hands the caller no structured reason and cannot
648
+ * / be told from a genuine fault. Under L1 the refusal is a value.
649
+ * /
650
+ * / The comment the engram carried is worth keeping because it names what went wrong: `null`
651
+ * / collapsed "unknown jobId" and "not authorized", and the product rendered the wrong conclusion
652
+ * / from it — the marketplace UI printed "Job not found (or not yet visible)" at a caller who was
653
+ * / merely unauthorized. Job existence is not the secret: `getJobCounts()` is ungated.
654
+ */
655
+ getJob: ActorMethod<[string], Result_14>;
656
+ /**
657
+ * / PUBLIC: aggregate counts that identify nobody — and already public on the engram, which is
658
+ * / what made `listJobs`' existence-leak justification false.
659
+ */
660
+ getJobCounts: ActorMethod<[], JobCounts>;
661
+ /**
662
+ * / The sharpest of the family, and the one in a money path — the engram's own comment said so.
663
+ * /
664
+ * / `null` there collapsed THREE meanings: unknown jobId, not authorized, and NO RESULT SUBMITTED
665
+ * / YET. So a refusal presented as a claim about the WORK. Combined with the `buyer : Text` defect,
666
+ * / an EVM-rail buyer was refused permanently, polled, read `null` as "the seller delivered
667
+ * / nothing", and escalated to dispute — a fabricated refusal manufacturing a commercial conflict.
668
+ * /
669
+ * / Three outcomes, three answers now. And `Payer` (above) removes the root cause rather than
670
+ * / only labelling it.
671
+ */
672
+ getJobResult: ActorMethod<[string], Result_13>;
673
+ /**
674
+ * / Terminal money settlement — the seller gets paid. Honours the freeze exactly like every
675
+ * / other settle path; a settlement that ignored the freeze would make the freeze a suggestion.
676
+ * / PUBLIC: a job's state, and nothing else about it.
677
+ * /
678
+ * / ⟨0.16.0⟩ THE UNGATED TWIN OF `getJob`, AND IT MUST STAY UNGATED. `getJob` is allowed to refuse
679
+ * / precisely because this exists: an EVM-rail buyer has NO PRINCIPAL on this canister, so a
680
+ * / principal-gated read can never authorize them, and without a public status read they would
681
+ * / have no way to see the state of a job they paid for. `getJob`'s refusal names this method for
682
+ * / exactly that reason.
683
+ * /
684
+ * / Job existence is not the secret being kept — the payload is. Status and nothing more.
685
+ * /
686
+ * / The engram returned `?EngramJobStatus`, conflating "no such job" with a null-ish answer. Here
687
+ * / a missing job is `#NotFound`, which is a fact rather than an absence a caller has to interpret.
688
+ */
689
+ getJobStatus: ActorMethod<[string], Result_12>;
690
+ /**
691
+ * / PUBLIC: the market's spend limits, with the caller rosters REDACTED.
692
+ * /
693
+ * / The limits themselves are already public — they are advertised inside every 402 challenge, so
694
+ * / withholding them here would hide nothing while making the market unquotable. `allowedCallers`
695
+ * / and `blockedCallers` are different in kind: an access-control roster, and a world-readable
696
+ * / blocklist tells everyone who has been blocked. Redacted to `null`, which reads as "not
697
+ * / disclosed" rather than as "empty" — an empty roster and a withheld one are different facts.
698
+ * /
699
+ * / Reads the GLOBAL policy. The engram called `getPolicy(self)`, i.e. the effective policy for
700
+ * / the canister acting as its own payer — which silently returns a self-override if one exists,
701
+ * / so the published limits could differ from the ones actually applied to buyers.
702
+ */
703
+ getPaymentPolicy: ActorMethod<[], SpendingPolicy>;
704
+ /**
705
+ * / and nothing is aggregated across sellers.
706
+ * /
707
+ * / THE FIGURES ARE COMPUTED, NOT READ FROM THE CANISTER-WIDE COUNTERS. `payments`' scalars are
708
+ * / every seller's money added together; handing them to one seller would overstate their revenue
709
+ * / by the entire market. Service revenue is derived per seller from settled jobs on services they
710
+ * / operate.
711
+ * /
712
+ * / Anonymous is refused rather than answered with zeroes. A zero here is a real business fact —
713
+ * / "you have sold nothing" — and returning it to a caller who simply has no identity is the
714
+ * / fabricated-empty defect wearing a number instead of a list.
715
+ */
716
+ getRevenueSummary: ActorMethod<[], Result_11>;
717
+ /**
718
+ * / PUBLIC: what a buyer can learn about a seller, and the whole of it.
719
+ * /
720
+ * / The ENGRAM ID is the point of this read. This market runs no reputation system and issues no
721
+ * / badges, so the honest trust signal is not a verdict we invent — it is a pointer to the record
722
+ * / the seller already keeps. A buyer who wants to know whether this seller is a verified human,
723
+ * / what their audit chain says, or how long they have existed asks THAT engram directly, and gets
724
+ * / an answer this market cannot shade.
725
+ * /
726
+ * / `verified` is about ownership at a moment in time and nothing else. It is not an endorsement,
727
+ * / and the field name is the strongest claim it makes.
728
+ */
729
+ getSellerStatus: ActorMethod<[Principal], Result_10>;
730
+ /**
731
+ * / PUBLIC: aggregate session counts. Identifies nobody, and the same reasoning as getJobCounts —
732
+ * / which is also what made `listJobs`' old "no existence leak" defence false.
733
+ */
734
+ getSessionCounts: ActorMethod<[], SessionCounts>;
735
+ http_request: ActorMethod<[HttpRequest], HttpResponse>;
736
+ /**
737
+ * / ⟨2026-09-30, ic402 2.17.0⟩ THE TWO PAID ROUTES HERE STAY ON `gate.settle`, AND THAT IS WHY NO
738
+ * / FLOW MAY LEAVE A STANDING ALLOWANCE TO THIS MARKET. An HTTP request arrives with no caller to
739
+ * / check (the gateway calls anonymously), so `settleFrom` cannot apply and ic402 says to keep
740
+ * / `settle` on HTTP paths. Such a settle is authenticated only by the payer's ICRC-2 allowance:
741
+ * / anyone who names a principal holding an unspent allowance to this canister can spend it here.
742
+ * / The defence is on the paying side — approve exactly the price plus one ledger fee, expiring
743
+ * / within minutes, immediately before paying (the SDK's `MarketClient` does). WHAT WOULD MAKE
744
+ * / THIS WRONG: an HTTP route that could authenticate its payer, or a flow of ours that approves
745
+ * / more than one payment's worth or without an expiry.
746
+ * /
747
+ * / ⟨CORRECTED 2026-09-30 — the owner's answer "1 B"⟩ The paragraph above is history. No web route
748
+ * / settles an ICP-rail payment any more, so none spends an allowance and none can be used against
749
+ * / a standing one. The one `gate.settle` left is on /service/, reached only with an EVM (`eip155:`)
750
+ * / payment carrying the buyer's own EIP-3009 authorization — a signature that names the payment and
751
+ * / travels privately in the request. An ICP-rail (ckUSDC) payment offered there is refused before
752
+ * / any settle and pointed at the Candid `createJob`; /content/ sells nothing over the web
753
+ * / (`contentNotSoldOverHttp`). ckUSDC is taken only by the Candid calls, which check their caller.
754
+ * / WHAT WOULD MAKE THIS WRONG: a web route that settles a payment whose network is not `eip155:`.
755
+ */
756
+ http_request_update: ActorMethod<[HttpRequest], HttpResponse>;
757
+ /**
758
+ * / PUBLIC: a wallet calls this BEFORE its user has any standing here — that is the whole point of
759
+ * / the call — so gating it would make the message unreadable at exactly the moment it is needed,
760
+ * / and a signature given without it is a signature given blind.
761
+ * /
762
+ * / ICRC-21 consent messages for this market's own state-changing methods.
763
+ * /
764
+ * / Every canister a signer is asked to sign FOR needs this, or the wallet cannot render what it
765
+ * / is approving. Two shape facts, both learned from live signer failures and both load-bearing:
766
+ * /
767
+ * / · `user_preferences : {}` accepts ANY record. The spec nests language at
768
+ * / user_preferences.metadata.language, and declaring the flat `{ language }` TRAPPED every
769
+ * / real signer's request ("did not find field language in record"; OISY, 2026-07-25).
770
+ * / `record {}` is a supertype of every record, so it decodes any signer's preferences without
771
+ * / trapping and is a widening — therefore compatible — interface.
772
+ * / · The reply REQUIRES `metadata` beside `consent_message`. Omitting it made OISY fail to
773
+ * / decode the reply ("Cannot find required field metadata", 2026-07-26). language is "en"
774
+ * / because the messages ARE English; the field states what they are, not what was asked for.
775
+ * /
776
+ * / The fallback says the method name rather than inventing a description. A wallet showing an
777
+ * / approving-sounding sentence for a method this canister does not recognise is the signing-time
778
+ * / version of a fabricated answer.
779
+ */
780
+ icrc21_canister_call_consent_message: ActorMethod<
781
+ [
782
+ {
783
+ arg: Uint8Array | number[];
784
+ method: string;
785
+ user_preferences: {};
786
+ },
787
+ ],
788
+ | {
789
+ Ok: {
790
+ metadata: {
791
+ utc_offset_minutes: [] | [number];
792
+ language: string;
793
+ };
794
+ consent_message: { GenericDisplayMessage: string };
795
+ };
796
+ }
797
+ | { Err: { description: string; error_code: bigint } }
798
+ >;
799
+ /**
800
+ * / PUBLIC: whether this market is trading at all. A buyer whose job creation refuses needs to be
801
+ * / able to tell "the market is halted" from "my request was wrong", and only this canister can
802
+ * / say which. Withholding it would turn an announced halt into an unexplained failure, which is
803
+ * / the fabricate-on-refusal shape read from the other side.
804
+ * /
805
+ * / The market's own freeze — trade halted for everyone here, by this canister's admin.
806
+ * /
807
+ * / DELIBERATELY NOT the engram's freeze, which stops one owner's engram signing at its guardian's
808
+ * / word. The two were a single field for as long as they shared a struct, and a guardian who
809
+ * / froze their own engram could not tell they had not also frozen a marketplace. Separate facts,
810
+ * / separate authorities, separate switches.
811
+ */
812
+ isTradeFrozen: ActorMethod<[], boolean>;
813
+ /**
814
+ * / `total` is the head counter, not the row count: this is a bounded ring, so a page that
815
+ * / reported only what it returned would make a trimmed log look complete.
816
+ */
817
+ listAuditEntries: ActorMethod<[bigint, bigint], Result_8>;
818
+ /**
819
+ * / Admin AND the enrolled viewers themselves — L8's roster rule. A viewer who cannot see the
820
+ * / roster cannot tell whether their own enrolment survived a rotation.
821
+ */
822
+ listAuditViewers: ActorMethod<[], Result_9>;
823
+ /**
824
+ * / PUBLIC: the catalogue is the storefront. A shop that refuses to say what it sells to
825
+ * / anyone who has not already bought is not a shop.
826
+ */
827
+ listContent: ActorMethod<[bigint, bigint], Page_6>;
828
+ /**
829
+ * / L11 names this canister's reason for having a denial log at all: the commerce surface is where
830
+ * / the fabricated-empty class was born, and a refusal that leaves no trace cannot be counted,
831
+ * / alerted on, or disproved.
832
+ */
833
+ listDenialEntries: ActorMethod<[bigint, bigint], Result_8>;
834
+ /**
835
+ * / Purchase history for one endpoint: its creator sees every row, a buyer sees their own.
836
+ * /
837
+ * / ⟨0.16.0⟩ Two defects close here at once, and they are the same defect wearing two hats.
838
+ * /
839
+ * / The engram matched a buyer with `buyer == Principal.toText(msg.caller)` — string equality
840
+ * / against a field that holds a principal on one rail and a `0x` address on the other. So an
841
+ * / EVM-rail buyer could not see their OWN purchases, ever. `Payer` makes that an arm match.
842
+ * /
843
+ * / And the filtered rows were dropped SILENTLY: a buyer reading someone else's endpoint got a
844
+ * / short list with nothing saying rows had been removed, indistinguishable from an endpoint with
845
+ * / few sales. `withheld` now counts them, so "no purchases here" and "not yours to see" are
846
+ * / different answers — without naming whose they were.
847
+ */
848
+ listEndpointPurchases: ActorMethod<[string, bigint, bigint], Result_7>;
849
+ /**
850
+ * / PUBLIC: the shelves, like the catalogue. `#Deleted` listings are excluded from an
851
+ * / unfiltered read and COUNTED in `withheld` — a shop with three deleted listings and a shop with
852
+ * / none look different, which is the honest answer, without publishing what was withdrawn.
853
+ */
854
+ listEndpoints: ActorMethod<[[] | [EndpointStatus], bigint, bigint], Page_3>;
855
+ /**
856
+ * / ⟨0.16.0⟩ THE `listJobs` FIX — the second of the two fabricated empties L11 names.
857
+ * /
858
+ * / The engram's version ended its authorization check with `if (not (isOwner or
859
+ * / isServiceOperator)) { return [] }`, and its own `.did` comment declared the behaviour on the
860
+ * / wire: "Fails closed to [] for an unknown service or an unauthorized caller (no existence
861
+ * / leak)." So a refused caller and a service with genuinely no jobs were the same answer, and it
862
+ * / was documented as a feature.
863
+ * /
864
+ * / THE EXISTENCE-LEAK JUSTIFICATION DOES NOT HOLD, checked at the site rather than argued: the
865
+ * / sibling `getJobCounts()` is an UNGATED public query over the same registry, so the number of jobs
866
+ * / is already world-readable. Nothing was being protected — the empty list hid the refusal from
867
+ * / the person refused, and hid it from every honesty gate too.
868
+ * /
869
+ * / It could not be caught mechanically either, and that is the more interesting half. The gates
870
+ * / scan for a known set of authorization helpers; this method's check is two LOCAL BOOLEANS
871
+ * / (`isOwner`, `isServiceOperator`), so the analyzer matched nothing and reported no finding. Its
872
+ * / siblings `getJob` and `getJobResult` had already been converted to traps for exactly this
873
+ * / defect; this one survived because it was written differently, not because it was ruled safe.
874
+ * /
875
+ * / Now: `#Refused` when the caller may not ask, `#NotFound` when the service does not exist —
876
+ * / two facts that were one empty list.
877
+ */
878
+ listJobs: ActorMethod<[string, [] | [JobStatus], bigint, bigint], Result_6>;
879
+ /**
880
+ * / The parked withdrawals belonging to this caller, so an unresolved payout is discoverable
881
+ * / rather than something a seller has to already know the id of.
882
+ * /
883
+ * / PAGED, and NOT taken as a bounded exemption, though the temptation was real: a seller parks a
884
+ * / withdrawal only when a ledger call rejects, and each withdrawal zeroes their balance — so the
885
+ * / list is 0 or 1 in every ordinary history. It is not STRUCTURALLY bounded, which is the test
886
+ * / the page-shape rule actually applies: a run of ledger outages across a run of sales
887
+ * / accumulates rows with nothing to stop it. A bare array that silently truncated would be
888
+ * / indistinguishable from "you have no other unresolved payouts", and this is money.
889
+ * /
890
+ * / `withheld` is always 0 here. The filter is by owner and a caller cannot own a row they may
891
+ * / not see, so nothing is ever hidden from them — unlike `listEndpointPurchases`, where a
892
+ * / non-owner's view withholds other buyers' rows. Stated because a reader comparing the two
893
+ * / should know the zero is a fact about this surface, not an unimplemented field.
894
+ */
895
+ listMyPendingWithdrawals: ActorMethod<[bigint, bigint], Result_5>;
896
+ /**
897
+ * / ⟨0.16.0⟩ `listAllServices` FOLDS in as `includeDisabled`.
898
+ * /
899
+ * / The engram had two methods because the visibility rule differed: everyone saw enabled
900
+ * / services; the owner and active sellers also saw disabled drafts. On a shared market that
901
+ * / rule becomes per-seller — you see every enabled service, plus YOUR OWN disabled drafts — which
902
+ * / is one query with a flag rather than two methods with divergent gates.
903
+ * /
904
+ * / `withheld` counts other sellers' drafts that the flag asked for and the caller may not see. A
905
+ * / seller can tell "no drafts" from "not yours to see" without learning whose they are.
906
+ */
907
+ listServices: ActorMethod<[boolean, bigint, bigint], Page>;
908
+ /**
909
+ * / ⟨0.16.0⟩ THE APPROVAL PARAMETER IS GONE, and its absence is the split working.
910
+ * /
911
+ * / The engram's openSession took an `approvalId` and could answer `#approvalPending` — because
912
+ * / there, opening a session was THE ENGRAM SPENDING ITS OWNER'S MONEY, so the owner's approval
913
+ * / queue gated it.
914
+ * /
915
+ * / Here the caller is a BUYER. If that buyer is an engram, its owner's approval was checked on
916
+ * / the engram before it ever called this canister — approvals stayed with custody, and so did the
917
+ * / signing they gate. The market receives a payment signature that someone already authorised;
918
+ * / asking it to also adjudicate whose approval backs that signature would put one owner's custody
919
+ * / policy on a canister shared with everyone else's.
920
+ * /
921
+ * / So a whole return arm disappears rather than moving. That is what a correct seam looks like:
922
+ * / the market got simpler because the responsibility went where it belonged, not because anything
923
+ * / was dropped.
924
+ * /
925
+ * / ⚠ ⟨2026-09-02 — OWNER-RULED: MARKET SESSIONS ARE NOT REQUIRED FOR NOW. The interfaces stay;
926
+ * / this note is what makes them honest.⟩ THE SESSION LIFECYCLE HERE IS INERT: a session can be
927
+ * / opened, and it can be closed or refunded, but it can never be SPENT. `gate.consumeVoucher` has
928
+ * / **zero call sites in this canister** — the only two in the estate are on the ENGRAM, which
929
+ * / runs its own separate paid-memory rail with its own gateway, `sess-N` counter and escrow
930
+ * / subaccount. So a market session is deposit-in and full-refund-out, and a buyer who opens one
931
+ * / gets their money back minus two ckUSDC ledger fees, having bought nothing.
932
+ * /
933
+ * / WHY THE METHODS ARE KEPT RATHER THAN DELETED: they are a complete, reviewable lifecycle
934
+ * / (open / end / forceClose / forceResolve / recoverEscrow / getSessionCounts) against a real
935
+ * / escrow, and the ruling is "not required for now", not "never". Deleting them would mean
936
+ * / re-deriving the seam when session billing is wanted, and the market is WITHHELD at 0.16.0 —
937
+ * / in neither environment — so nothing here is reachable by a customer today regardless.
938
+ * /
939
+ * / WHAT WOULD MAKE THIS SAFE TO ENABLE: a voucher-spend path — something on this canister that
940
+ * / calls `gate.consumeVoucher` and delivers what the voucher paid for. Until that exists, the
941
+ * / two `#Session` billing refusals say session billing is UNAVAILABLE rather than pointing
942
+ * / buyers at `openSession`, which is what they used to do.
943
+ * /
944
+ * / ⟨2026-09-30, ic402 2.17.0⟩ That future spend path calls `gate.consumeVoucherFrom(msg.caller, …)`,
945
+ * / not the bare `consumeVoucher`: the signed fallback is off on this canister, so the bare call
946
+ * / refuses every voucher, and only the session key calling as itself may spend a session.
947
+ */
948
+ openSession: ActorMethod<[SessionConfig, PaymentSignature], Result_4>;
949
+ /**
950
+ * / RENAMED from `requestSession` (census tier-3 #21): it is a pure dry run — a quote for a session
951
+ * / the caller has not opened and is not committed to. `request` read as an action with an effect.
952
+ * /
953
+ * / PUBLIC: a price list nobody can read is not a price list, and this is the market's. ⟨The
954
+ * / sentence was already here as "Ungated:"; only the marker the L8 gate greps for was missing,
955
+ * / which is why this method read as undefended when it was not.⟩
956
+ * / ⟨CORRECTED 2026-08-24 — this said "⟨L7⟩ UPDATE, NOT QUERY" and cited a market ruling that
957
+ * / DEC-107 had already closed.⟩ QUERY, per the ruled quote convention: FAST READS. Both
958
+ * / `quotePayment` and `previewOpenSession` become queries, and L7's open-ruling exception
959
+ * / retires with them — so the argument written here for keeping it an update was arguing the
960
+ * / losing side of a decision already made, and was added the same day by not reading forward
961
+ * / to the ruling. `gate.offerSession` is pure — it validates the intent and returns it — so
962
+ * / nothing forced the update in the first place.
963
+ * /
964
+ * / ONE-REPLICA CAVEAT, stated here because the ruling requires it at both sites: a query is one
965
+ * / replica's word and is NOT a settleable challenge. Nothing quoted here can be redeemed. The
966
+ * / commitment happens in `openSession`, which IS a certified update call, and a buyer who needs
967
+ * / the price attested rather than quoted takes it from that reply.
968
+ * /
969
+ * / ⟨2026-10-02⟩ Answers the house `Types.SessionIntent` — ic402's intent with `expiry` spelled
970
+ * / `expiryNs`. `openSession` hands ic402 its own record, from `sessionIntent()` below.
971
+ */
972
+ previewOpenSession: ActorMethod<[], SessionIntent>;
973
+ /**
974
+ * / PUBLIC: what it costs to pay this market a given amount, on every rail it settles.
975
+ * /
976
+ * / ⟨0.16.0⟩ Reshaped from `getPaymentRequirements(amount) : [PaymentRequirement]`. A bare array
977
+ * / was a `get*` returning a list, which reads like a collection to page through; this is a QUOTE,
978
+ * / a single answer to a single question, and it now says so in its name and its type.
979
+ * /
980
+ * / The quote ECHOES the amount it priced. A caller comparing this to a later 402 challenge is
981
+ * / then comparing two stated numbers instead of assuming the one they sent came back unchanged.
982
+ * /
983
+ * / Zero is refused. ic402's requirement builder traps on a zero amount, and a quote for nothing
984
+ * / is not a question this canister can answer — better a legible refusal than a trap in the
985
+ * / caller's own callback.
986
+ * /
987
+ * / ⟨CORRECTED 2026-10-02 — the nonce is GONE from the quote; the two paragraphs below are kept as
988
+ * / the record of why.⟩ Each requirement is now a `QuotedRequirement`: ic402's requirement without
989
+ * / its `nonce` (and with `expiry` spelled `expiryNs`). The paragraphs below describe the throwaway
990
+ * / that was published until this date; the pre-cut review recommended dropping it over ratifying
991
+ * / it, and it was dropped. "Do not pay against it" is now enforced by there being nothing to pay
992
+ * / against.
993
+ * /
994
+ * / ⚠ THE NONCE IN EACH REQUIREMENT IS A THROWAWAY — DO NOT PAY AGAINST IT. `requireAll` mints a
995
+ * / server nonce with a HashMap put, and this is a QUERY, so the write is discarded on return.
996
+ * / The nonce is published and does not exist. Signing a payment against it settles as
997
+ * / `#expired("Server nonce expired, already used, or bound to a different network/token")`,
998
+ * / which is wrong on every clause and points a caller back here for another dead one.
999
+ * /
1000
+ * / That is by design, not an oversight now excused: a quote is a PRICE LIST, not a settleable
1001
+ * / challenge. The HTTP surface of this same canister already draws the line in the same place —
1002
+ * / `/discovery/resources` is a catalog with a throwaway nonce, while `/content` and `/service`
1003
+ * / return `httpUpgrade()` so the challenge is minted in an UPDATE and persists. This is the
1004
+ * / Candid twin of `/discovery/resources`, and it was the only one of the pair not saying so.
1005
+ * / ⟨CORRECTED 2026-09-30⟩ Only `/service` upgrades now; `/content` sells nothing over the web and
1006
+ * / answers 410 from the query. And unlike this quote, the web catalog lists EVM requirements only.
1007
+ * /
1008
+ * / TO GET A PAYABLE CHALLENGE, call the resource: `getContent(contentId, null)` or
1009
+ * / `createJob(serviceId, params, null)`. Both are updates, so the nonce they mint survives.
1010
+ * / This matters most on the ckUSDC rail, which is where customer payments settle: ICP has no
1011
+ * / on-chain nonce, so `settle` ALWAYS requires the server one. A conformant EVM x402 client
1012
+ * / sends no server nonce at all and is unaffected.
1013
+ */
1014
+ quotePayment: ActorMethod<[bigint], Result_3>;
1015
+ /**
1016
+ * / Admin recovery: re-drive a job stuck mid-settlement — a broadcast EVM transfer whose outcome
1017
+ * / this canister never learned. Reads the chain and finishes what the settle started.
1018
+ * /
1019
+ * / Unstick, not decide: it does not choose an outcome, it discovers one. When it cannot, it says
1020
+ * / so and points at resolveJob, which is where a human decision belongs.
1021
+ * /
1022
+ * / ⟨2026-10-02, the payment library's refusal channel — audited at this site⟩ `#Conflict` here
1023
+ * / carries ic402's text, and ic402 answers with one text channel for every refusal. AUDITED:
1024
+ * / this method's own gate (`requireAdmin`) decides authorization before the library is called, and every
1025
+ * / text the library returns here is a STATE refusal (job missing, no parked tx, no confirm hook wired, the chain's answer) — including "not found", which
1026
+ * / arrives as `#Conflict` rather than `#NotFound`. Read the MESSAGE for which. This is the 0.16.0
1027
+ * / contract as ratified on 2026-10-02; giving the library one arm per kind of refusal is post-cut
1028
+ * / dependency work.
1029
+ */
1030
+ reconcileJob: ActorMethod<[string], Result_2>;
1031
+ /**
1032
+ * / Admin recovery for a session whose settlement was interrupted mid-flight. Same line as
1033
+ * / forceCloseSession: it completes what was already decided, it does not decide anything.
1034
+ * /
1035
+ * / Freeze-gated, unlike forceClose — reconciliation can PAY a seller, and a halt must stop money
1036
+ * / moving outward. Force-close only returns a buyer's own deposit, which a freeze must not trap
1037
+ * / (the same reasoning that leaves disputeJob un-gated).
1038
+ * /
1039
+ * / ⟨2026-10-02, the payment library's refusal channel — audited at this site⟩ `#Conflict` here
1040
+ * / carries ic402's text, and ic402 answers with one text channel for every refusal. AUDITED:
1041
+ * / this method's own gate (`requireAdmin`) decides authorization before the library is called, and every
1042
+ * / text the library returns here is a STATE refusal (session missing, not parked in #closing, no parked tx, no EVM deposit or sender configured, the chain's answer) — including "not found", which
1043
+ * / arrives as `#Conflict` rather than `#NotFound`. Read the MESSAGE for which. This is the 0.16.0
1044
+ * / contract as ratified on 2026-10-02; giving the library one arm per kind of refusal is post-cut
1045
+ * / dependency work.
1046
+ */
1047
+ reconcileSession: ActorMethod<[string], Result_2>;
1048
+ /**
1049
+ * / Settle a parked withdrawal by asking the ledger what happened, rather than assuming.
1050
+ * /
1051
+ * / Re-sends the IDENTICAL transfer — same amount, same fee, same `created_at_time`. Within
1052
+ * / ICRC-1's 24h deduplication window there are exactly two outcomes and both are conclusive:
1053
+ * / · `#Err(#Duplicate)` — the original DID execute. The seller has been paid; discard the
1054
+ * / parked record.
1055
+ * / · `#Ok` — the original did NOT execute, and this call has now paid it. Discard.
1056
+ * / Anything else leaves the record parked and retryable; it is never guessed at.
1057
+ * /
1058
+ * / Callable by the SELLER it belongs to. This pays only ever to the recorded seller, so a
1059
+ * / stranger calling it could not misdirect funds — but it is still scoped, because a parked
1060
+ * / withdrawal is the seller's business and its existence is a fact about their balance.
1061
+ * /
1062
+ * / The precedent is the cashier's `recoverPendingClaim`: same saga, same rail, same reason.
1063
+ */
1064
+ recoverContentWithdrawal: ActorMethod<[bigint], Result>;
1065
+ /**
1066
+ * / Admin recovery: return unconsumed escrow from a stuck or terminal session's own subaccount.
1067
+ * / THE ONE RECOVERY METHOD THAT MOVES REAL MONEY.
1068
+ * /
1069
+ * / It is on the right side of "an admin may unstick, and may not decide" for one structural
1070
+ * / reason, not by policy: THE DESTINATION IS NOT A PARAMETER. ic402 hardcodes the refund to
1071
+ * / `session.payer`, and the admin's principal appears nowhere in the transfer. The admin supplies
1072
+ * / the session, the token and an amount; they cannot supply a recipient. An admin can unstick a
1073
+ * / refund and cannot redirect one, and that is enforced by the shape of the call rather than by
1074
+ * / this comment.
1075
+ * /
1076
+ * / ic402 authorizes `caller == session.payer`, so the payer is read from the session and passed
1077
+ * / through — the same pattern the engram used, and NOT the seller-impersonation defect, because
1078
+ * / here the identity being passed is the one that RECEIVES the money rather than one being
1079
+ * / presented as the actor. The audit row records the real admin who forced it.
1080
+ * /
1081
+ * / Idempotent through the ledger: the first refund drains the subaccount, so a second call fails
1082
+ * / with insufficient funds rather than paying twice.
1083
+ * /
1084
+ * / ⟨2026-10-02, the payment library's refusal channel — audited at this site⟩ `#Conflict` here
1085
+ * / carries ic402's text, and ic402 answers with one text channel for every refusal. AUDITED:
1086
+ * / this method's own gate (`requireAdmin`; the library's own only-the-payer check cannot fire, because the payer is read from the session and passed through) decides authorization before the library is called, and every
1087
+ * / text the library returns here is a STATE refusal (an open session, nothing left to recover, the ledger's refusal) — including "not found", which
1088
+ * / arrives as `#Conflict` rather than `#NotFound`. Read the MESSAGE for which. This is the 0.16.0
1089
+ * / contract as ratified on 2026-10-02; giving the library one arm per kind of refusal is post-cut
1090
+ * / dependency work.
1091
+ * /
1092
+ * / ⟨2026-10-05, ic402 2.17.3 — beside the first line and the list above⟩ Escrow comes back only
1093
+ * / from a session that reads `closed`. A session that reads `closing` or `expired` is refused, with
1094
+ * / nothing moved — a fourth state refusal — so a "stuck" session here means one that
1095
+ * / `forceResolveSession` has closed first; recover it within 24 hours of that force.
1096
+ */
1097
+ recoverEscrow: ActorMethod<[string, TokenAmount], Result>;
1098
+ /**
1099
+ * / Register as a seller by naming the engram you own.
1100
+ * /
1101
+ * / The registry is asked, not trusted from the caller's word: `verifyEngramActiveOwner` confirms
1102
+ * / that THIS caller owns THAT engram and that it is #Active — which also means an abandoned
1103
+ * / engram cannot back a listing, since abandonment is terminal there and this market has no
1104
+ * / business inheriting a claim its owner walked away from.
1105
+ * /
1106
+ * / Re-registering is how a seller refreshes an expiring binding, and it is idempotent apart from
1107
+ * / the timestamp. The byte count SURVIVES re-registration — otherwise the quota would reset every
1108
+ * / thirty days, which is a quota in name only.
1109
+ */
1110
+ registerSeller: ActorMethod<[Principal], Result_1>;
1111
+ /**
1112
+ * / Register a paid service. Born DISABLED, like an endpoint and for the same reason: a listing
1113
+ * / that went live at creation would be sellable before its seller had checked it.
1114
+ * /
1115
+ * / ⚠ THIS NEARLY DID NOT MAKE THE MOVE. It was deleted from the engram with the rest of the
1116
+ * / commerce graft and was not written here until a downstream web client failed to compile
1117
+ * / against a market that had no way to create a service at all — sellers could enable, disable
1118
+ * / and list services, and could never make one. Recorded because the gap was invisible to every
1119
+ * / gate: the canisters compiled, the .did was well formed, and check-client-idls only sees names
1120
+ * / that ARE declared.
1121
+ * /
1122
+ * / `verificationMethod` stays a STRING with a parsed tail, exactly as the engram had it, because
1123
+ * / #BuyerConfirm carries a window ("BuyerConfirm:3600") and a bare variant cannot. The parse is
1124
+ * / total: an unrecognised method falls back to #AutoSettle rather than refusing, which is the
1125
+ * / engram's behaviour preserved deliberately — a seller mistyping a verification mode should get
1126
+ * / the safe default, not a service they cannot create.
1127
+ */
1128
+ registerService: ActorMethod<
1129
+ [
1130
+ string,
1131
+ string,
1132
+ ServiceType,
1133
+ PricingScheme,
1134
+ string,
1135
+ [] | [string],
1136
+ [] | [Uint8Array | number[]],
1137
+ ServiceDeliveryMethod,
1138
+ bigint,
1139
+ [] | [boolean],
1140
+ ],
1141
+ Result_2
1142
+ >;
1143
+ removeAuditViewer: ActorMethod<[Principal], Result_1>;
1144
+ /**
1145
+ * / Remove a per-payer override so that payer reverts to — and keeps TRACKING — the global policy.
1146
+ * /
1147
+ * / Its pair's only other "undo" was overwriting the override with a frozen copy of the global
1148
+ * / policy, which then stops following later global changes. That is why the two never travel
1149
+ * / apart: without this one, every override is permanent in effect.
1150
+ */
1151
+ removeCallerPolicy: ActorMethod<[Principal], Result_1>;
1152
+ /**
1153
+ * / ⟨0.16.0⟩ RULED 2026-08-17: THE SELLER RESOLVES. Not the market admin.
1154
+ * /
1155
+ * / The engram's `requireOwner` was coherent there because the engram's owner IS the seller — a
1156
+ * / dispute was between that owner and their buyer. Transcribing it here would have made the
1157
+ * / market admin the arbiter of commercial disputes between independent parties, moving their
1158
+ * / money: a business and probably a legal position, inherited by accident from a canister where
1159
+ * / "owner" meant something else.
1160
+ * /
1161
+ * / The ruling keeps the power where it already was rather than quietly relocating it to us.
1162
+ * /
1163
+ * / ⚠ THE ASYMMETRY IS REAL AND IS STATED, HERE AND ON THE WIRE. The accused judges. A seller can
1164
+ * / refuse a refund to a buyer who has already paid, and nothing on this canister overrides that:
1165
+ * / there is no admin override, no appeal, and no reputation system yet to price the behaviour.
1166
+ * / That is an honest description of who holds power in this market today, and a buyer is entitled
1167
+ * / to know it BEFORE they buy — which is why it is in the refusal text a buyer actually sees, not
1168
+ * / only in a comment they never will.
1169
+ * /
1170
+ * / Writing it down is also what makes it revisitable: when a reputation system or an escrow
1171
+ * / timeout arrives, this method is where the change lands and this comment is the argument it has
1172
+ * / to answer.
1173
+ * /
1174
+ * / ⟨2026-10-02, the payment library's refusal channel — audited at this site⟩ `#Conflict` here
1175
+ * / carries ic402's text, and ic402 answers with one text channel for every refusal. AUDITED:
1176
+ * / this method's own gate (the service's seller, checked above the library call) decides authorization before the library is called, and every
1177
+ * / text the library returns here is a STATE refusal (job missing, not in a resolvable state, a refund parked or failed) — including "not found", which
1178
+ * / arrives as `#Conflict` rather than `#NotFound`. Read the MESSAGE for which. This is the 0.16.0
1179
+ * / contract as ratified on 2026-10-02; giving the library one arm per kind of refusal is post-cut
1180
+ * / dependency work.
1181
+ */
1182
+ resolveDispute: ActorMethod<[string, boolean], Result_1>;
1183
+ /**
1184
+ * / Admin LAST RESORT: force a job to a terminal status when reconcileJob cannot determine one —
1185
+ * / a reverted or dead transaction that the chain will never resolve either way.
1186
+ * /
1187
+ * / ⚠ THIS IS THE ONE PLACE THE ADMIN LINE BENDS, AND IT IS NAMED SO IT CANNOT BE USED CASUALLY.
1188
+ * / Elsewhere on this canister an admin may unstick and may not decide; here the whole point is
1189
+ * / that no discoverable answer exists, so someone must choose whether the seller was paid or
1190
+ * / the buyer refunded. The narrowness is the safeguard: ic402 rejects any non-terminal target, so
1191
+ * / the choice is between #Settled, #Refunded and #Expired and cannot be used to reopen a job or
1192
+ * / move it sideways. Every use is a chained audit row naming the admin and the status they chose.
1193
+ * /
1194
+ * / `#other` fails closed. It is a placeholder for a job state this canister cannot name, and
1195
+ * / forcing a job into a state we cannot name is not a recovery.
1196
+ * /
1197
+ * / ⟨2026-10-02, the payment library's refusal channel — audited at this site⟩ `#Conflict` here
1198
+ * / carries ic402's text, and ic402 answers with one text channel for every refusal. AUDITED:
1199
+ * / this method's own gate (`requireAdmin`) decides authorization before the library is called, and every
1200
+ * / text the library returns here is a STATE refusal (job missing, not stuck in #Settling, a target that is not terminal) — including "not found", which
1201
+ * / arrives as `#Conflict` rather than `#NotFound`. Read the MESSAGE for which. This is the 0.16.0
1202
+ * / contract as ratified on 2026-10-02; giving the library one arm per kind of refusal is post-cut
1203
+ * / dependency work.
1204
+ */
1205
+ resolveJob: ActorMethod<[string, JobStatus], Result_1>;
1206
+ setAdmin: ActorMethod<[Principal], Result_1>;
1207
+ /**
1208
+ * / Override the policy for ONE payer — the market's per-buyer risk control.
1209
+ */
1210
+ setCallerPolicy: ActorMethod<[Principal, SpendingPolicy], Result_1>;
1211
+ /**
1212
+ * / ⟨0.16.0, L2.6⟩ `enableEndpoint` and `disableEndpoint` FOLD into one setter.
1213
+ * /
1214
+ * / They were byte-identical apart from the status they wrote and the word in their name, which is
1215
+ * / the definition of a boolean expressed as two methods. L2.6 rules one idiom for a boolean
1216
+ * / feature, and the fold also removes a real hazard: two methods meant two authorization checks
1217
+ * / to keep in step, and a divergence between them would have been invisible to a reader looking at
1218
+ * / either one alone.
1219
+ * /
1220
+ * / `#Deleted` stays a refusal in both directions and stays `#Conflict`, not `#Invalid`: the
1221
+ * / request is well-formed and permitted, the endpoint is simply in a terminal state — and calling
1222
+ * / that `#Invalid` would tell a caller to fix their request when nothing about it is wrong.
1223
+ */
1224
+ setEndpointEnabled: ActorMethod<[string, boolean], Result_1>;
1225
+ /**
1226
+ * / Set an endpoint's price. THE SELLER'S, not the admin's.
1227
+ * /
1228
+ * / requireEndpointOwner admits the market admin for the enable/disable pair, because a listing an
1229
+ * / admin cannot take down is a moderation problem. PRICE IS DIFFERENT: changing what a seller
1230
+ * / charges is trading on their behalf, and no recovery story needs it.
1231
+ */
1232
+ setEndpointPrice: ActorMethod<[string, bigint], Result_1>;
1233
+ /**
1234
+ * / A seller registers the EVM address their EVM-paid settlements are sent to.
1235
+ * /
1236
+ * / SELF-SCOPED: the address is keyed by `msg.caller`, so the only account a caller can change is
1237
+ * / their own — there is no gate to get wrong, because there is nothing to gate. The engram's
1238
+ * / `requireAgentOrOwner` here was protecting a canister-level roster that a shared market does
1239
+ * / not have. Anonymous is refused: an anonymous payout address is an address nobody can be paid at.
1240
+ * /
1241
+ * / Without one, an EVM-paid job's settlement FAILS CLOSED and rolls back — the market does not
1242
+ * / cross rails and pay an EVM seller out of the ICP pool.
1243
+ */
1244
+ setEvmSellerPayout: ActorMethod<[string], Result_1>;
1245
+ /**
1246
+ * / Set the market's global spending policy.
1247
+ * /
1248
+ * / The audit row records the LIMITS, not just the fact of a change, so a WIDENING is
1249
+ * / distinguishable from a tightening after the fact. A policy raise is the quiet half of most
1250
+ * / money incidents, and "policy changed" alone cannot tell an investigator which way.
1251
+ */
1252
+ setPaymentPolicy: ActorMethod<[SpendingPolicy], Result_1>;
1253
+ /**
1254
+ * / Whom this canister anchors to. Set by the admin at deploy; `sys` because it is protocol
1255
+ * / configuration, not a product surface.
1256
+ * /
1257
+ * / ⟨RENAMED 2026-10-02 from `sysSetRegistryId` — the sys-tier retier ruled 2026-08-24, executed
1258
+ * / under the owner's 2026-10-02 ruling to carry out the pre-cut interface decisions as
1259
+ * / recommended.⟩ The sentence above is why it was sys-named, and the retier is why it no longer
1260
+ * / is: the `sys` prefix names the canister-to-canister tier, whose callers are other canisters,
1261
+ * / and this method's only caller is a PERSON — the market's admin, at deploy. Keeping it there
1262
+ * / made "a `sys` method has no human caller" false, and so uncheckable. A plain admin setter
1263
+ * / (`setAdmin`'s sibling) is what it always was.
1264
+ */
1265
+ setRegistryId: ActorMethod<[Principal], Result_1>;
1266
+ /**
1267
+ * / ⟨0.16.0, L2.6⟩ enableService + disableService FOLD, same as the endpoint pair.
1268
+ * /
1269
+ * / Deliberately NOT admin-overridable, unlike endpoints. Disabling a seller's service is a
1270
+ * / commercial act against that seller, and an admin who needs to remove a listing should do it
1271
+ * / through a recorded moderation path rather than by silently flipping a flag that looks like the
1272
+ * / seller did it. Endpoints allow the admin override because a deleted endpoint is already
1273
+ * / terminal and visible; a disabled service looks like the seller's own choice.
1274
+ * /
1275
+ * / ⚠ `#Conflict` HERE ALSO COVERS "NOT THE SELLER" — the same ic402 seam as `claimJob`,
1276
+ * / `confirmJob` and `disputeJob`. `enableService`/`disableService` return `Service not found`
1277
+ * / (properly `#NotFound`) and **`Not the seller`** (properly `#Refused`) as plain strings, so
1278
+ * / the arm is gone before this method sees it. Read the MESSAGE, not the arm.
1279
+ * / ⟨2026-08-21; the project's backlog carries the three costed fixes and why none is a
1280
+ * / one-liner.⟩
1281
+ * / ⟨CORRECTED 2026-10-02, audited at this site — the paragraph above no longer holds here.⟩
1282
+ * / `requireServiceSeller` now runs BEFORE the library: a missing service is refused `#NotFound`
1283
+ * / and another seller `#Refused`, by this canister, with its own sentences. The library is then
1284
+ * / called with the caller already proven to be the seller, so its "Not the seller" and "Service
1285
+ * / not found" texts cannot reach the `#Conflict` arm below except across a race with a deletion.
1286
+ * / The seam is closed on this method by the gate, not by the library; the others keep their
1287
+ * / caveats.
1288
+ */
1289
+ setServiceEnabled: ActorMethod<[string, boolean], Result_1>;
1290
+ /**
1291
+ * / A seller submits a finished job's result.
1292
+ * /
1293
+ * / AUTHORITY IS THE JOB'S SELLER, checked by ic402 against the claim — not "a seller of this
1294
+ * / canister", which on a shared market would mean any seller could submit results for any other
1295
+ * / seller's jobs. The engram's `requireAgentOrOwner` was a canister-level gate that made sense
1296
+ * / only while one canister meant one seller.
1297
+ * /
1298
+ * / FREEZE-GATED because it can MOVE MONEY: the auto-settling verification modes (#AutoSettle /
1299
+ * / #HashMatch / #ZkGroth16) pay the seller inside submitResult. Only #BuyerConfirm defers to
1300
+ * / confirmJob. A reader who assumes "submitting a result is not a payment" is wrong for three of
1301
+ * / the four modes.
1302
+ * /
1303
+ * / ⚠ `#Conflict` HERE ALSO COVERS "NOT THE ASSIGNED OPERATOR" — a refusal of the caller's
1304
+ * / STANDING, not of the job's state. ⟨2026-10-02, audited at this site⟩ ic402's `submitResult`
1305
+ * / checks the caller against the job's operator itself and answers with one text channel, so
1306
+ * / "Not the assigned operator" and "Job not assigned" arrive here exactly as "Cannot submit result
1307
+ * / in status: …" does. A caller that branches on the arm retries a submission that can never be
1308
+ * / theirs. Read the MESSAGE, not the arm. This is the 0.16.0 contract as ratified on 2026-10-02;
1309
+ * / giving the library one arm per kind of refusal is post-cut dependency work.
1310
+ */
1311
+ submitJobResult: ActorMethod<
1312
+ [string, Uint8Array | number[], [] | [Uint8Array | number[]], [] | [bigint]],
1313
+ Result_1
1314
+ >;
1315
+ /**
1316
+ * / Upload a whole file in one call.
1317
+ */
1318
+ uploadContent: ActorMethod<[string, string, Uint8Array | number[]], Result_1>;
1319
+ /**
1320
+ * / Push one chunk of a started upload. NOT charged — uploadContentInit already reserved the
1321
+ * / declared total, so charging again here would bill the same bytes twice.
1322
+ */
1323
+ uploadContentChunk: ActorMethod<[string, bigint, Uint8Array | number[]], Result_1>;
1324
+ /**
1325
+ * / Begin a chunked upload. The WHOLE declared size is charged here, up front.
1326
+ * /
1327
+ * / Charging at init rather than per chunk is the point: a per-chunk charge would let a seller
1328
+ * / begin an upload that cannot finish, and discover it only after claiming most of the memory.
1329
+ * / Reserving the declared total means an over-quota upload is refused before its first byte lands.
1330
+ */
1331
+ uploadContentInit: ActorMethod<[string, string, bigint, bigint], Result_1>;
1332
+ /**
1333
+ * / The buyer-facing half of the same check, kept because it answers a different question: "is my
1334
+ * / grant still good", asked BEFORE spending a round trip on a chunk. Documented in ACCESS-CONTROL
1335
+ * / as the buyer's pre-flight.
1336
+ */
1337
+ verifyGrant: ActorMethod<[AccessGrant], Result_1>;
1338
+ /**
1339
+ * / Withdraw everything this caller has earned from content sales, to their own principal.
1340
+ * /
1341
+ * / NO DESTINATION ARGUMENT, and that is the security property rather than a missing feature: the
1342
+ * / funds go to `msg.caller` and nowhere else, so a stolen or mis-signed call cannot redirect a
1343
+ * / seller's balance to an attacker's account. A seller who wants the money elsewhere moves it
1344
+ * / from their own account, where they are the only signer.
1345
+ * /
1346
+ * / NOT GATED ON `requireSeller`. A seller binding expires and can be revoked; earnings do not.
1347
+ * / Gating withdrawal on current seller status would strand the balance of anyone whose engram
1348
+ * / lapsed after they sold — money owed, permanently unreachable, for a reason unrelated to the
1349
+ * / debt. The gate is the debt itself: you may withdraw exactly what you are owed.
1350
+ */
1351
+ withdrawContentRevenue: ActorMethod<[], Result>;
1352
+ }
1353
+ export declare const idlFactory: IDL.InterfaceFactory;
1354
+ export declare const init: (args: { IDL: typeof IDL }) => IDL.Type[];