@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,3839 @@
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 About {
6
+ verifiedHuman: boolean;
7
+ guardianCount: bigint;
8
+ totalMemoryWrites: bigint;
9
+ lastAgentWriteAtNs: [] | [bigint];
10
+ distinctReaderPrincipals: bigint;
11
+ lastWriteAtNs: [] | [bigint];
12
+ totalBackupSize: bigint;
13
+ backupCount: bigint;
14
+ lastAgentReadAtNs: [] | [bigint];
15
+ firstWriteAtNs: [] | [bigint];
16
+ agentCount: bigint;
17
+ paidMemoryReadEnabled: boolean;
18
+ version: string;
19
+ paymentsFrozen: boolean;
20
+ agentMemoryWrites: bigint;
21
+ agentMemoryReads: bigint;
22
+ auditLogSize: bigint;
23
+ memoryFileCount: bigint;
24
+ firstAgentWriteAtNs: [] | [bigint];
25
+ lastReadAtNs: [] | [bigint];
26
+ writesPaused: boolean;
27
+ distinctReaderClients: bigint;
28
+ totalMemoryReads: bigint;
29
+ walletActivatedAtNs: [] | [bigint];
30
+ encryptionEnabled: boolean;
31
+ paidMemoryWriteEnabled: boolean;
32
+ }
33
+ export interface ActionAuth {
34
+ signature: Uint8Array | number[];
35
+ pubkey: Uint8Array | number[];
36
+ nonce: bigint;
37
+ }
38
+ export interface ActivitySnapshot {
39
+ atNs: bigint;
40
+ memoryReads: bigint;
41
+ memoryWrites: bigint;
42
+ }
43
+ export interface AgentCard {
44
+ x402Support: boolean;
45
+ name: string;
46
+ description: string;
47
+ services: Array<ServiceEntry>;
48
+ }
49
+ export type AgentEndReason =
50
+ | { Resigned: null }
51
+ | { OwnerRevoked: null }
52
+ | { Reset: null }
53
+ | { KillSwitch: null }
54
+ | { GuardianRevoked: null };
55
+ export interface AgentEnding {
56
+ day: bigint;
57
+ reason: AgentEndReason;
58
+ }
59
+ export interface AgentPaymentSignatures {
60
+ agent: Principal;
61
+ signedToday: bigint;
62
+ root: Principal;
63
+ }
64
+ export interface AgentPermissions {
65
+ canReadMemory: boolean;
66
+ scopes: [] | [Array<string>];
67
+ canReadBackup: [] | [boolean];
68
+ callsPerMinute: bigint;
69
+ canAppendMemory: boolean;
70
+ canReadWallet: boolean;
71
+ }
72
+ export interface AgentRecord {
73
+ status: AgentStatus;
74
+ earlierKeys: Array<HeldKey>;
75
+ permissions: AgentPermissions;
76
+ principal: Principal;
77
+ keyRotationCount: bigint;
78
+ publicKeyHash: [] | [string];
79
+ pairedAtNs: bigint;
80
+ enrolment: EnrolmentProof;
81
+ lastSeenNs: bigint;
82
+ name: string;
83
+ root: Principal;
84
+ ended: [] | [AgentEnding];
85
+ keyNomination: [] | [KeyNomination];
86
+ keyRotatedAtNs: bigint;
87
+ keyHeldFrom: LogPosition;
88
+ }
89
+ export type AgentStatus = { Active: null } | { Resigned: null } | { Revoked: null };
90
+ export interface AgentWriteReview {
91
+ cursor: bigint;
92
+ head: bigint;
93
+ rows: Array<AgentWriteRow>;
94
+ earliest: bigint;
95
+ capped: boolean;
96
+ }
97
+ export interface AgentWriteRow {
98
+ source: [] | [string];
99
+ path: [] | [string];
100
+ entry: AuditEntry;
101
+ version: [] | [bigint];
102
+ connector: [] | [string];
103
+ }
104
+ export interface AlertConfig {
105
+ url: [] | [string];
106
+ money: boolean;
107
+ classes: [] | [Array<[string, boolean]>];
108
+ agentWrites: boolean;
109
+ guardian: boolean;
110
+ approvals: boolean;
111
+ }
112
+ export interface AlertStatus {
113
+ lastDeliveredAtNs: [] | [bigint];
114
+ failures: bigint;
115
+ totalAudit: bigint;
116
+ cursor: bigint;
117
+ disabled: boolean;
118
+ config: AlertConfig;
119
+ }
120
+ export interface AnchorPushStatus {
121
+ anchorTickAtNs: [] | [bigint];
122
+ okAtNs: [] | [bigint];
123
+ cadenceSeconds: bigint;
124
+ attemptTotal: bigint;
125
+ currentTotal: bigint;
126
+ timerTickAtNs: [] | [bigint];
127
+ okTotal: bigint;
128
+ carrierArmedAtNs: bigint;
129
+ attemptAtNs: [] | [bigint];
130
+ skipCursor: bigint;
131
+ lastError: string;
132
+ }
133
+ export interface ApprovalRequest {
134
+ id: string;
135
+ expiresAtNs: bigint;
136
+ status: ApprovalStatus;
137
+ denialReason: [] | [string];
138
+ policyField: string;
139
+ approvedBy: [] | [Principal];
140
+ createdAtNs: bigint;
141
+ approvedAtNs: [] | [bigint];
142
+ binding: string;
143
+ operation: string;
144
+ rationale: string;
145
+ policyLimit: bigint;
146
+ caller: Principal;
147
+ amount: bigint;
148
+ }
149
+ export type ApprovalStatus =
150
+ { Used: null } | { Approved: null } | { Denied: null } | { Expired: null } | { Pending: null };
151
+ export interface AuditEntry {
152
+ id: bigint;
153
+ entryHash: Uint8Array | number[];
154
+ callerRole: Role;
155
+ operation: string;
156
+ details: string;
157
+ caller: Principal;
158
+ success: boolean;
159
+ timestampNs: bigint;
160
+ }
161
+ export interface AuditHead {
162
+ headHash: Uint8Array | number[];
163
+ size: bigint;
164
+ }
165
+ export type AuthorityClass =
166
+ { standingAuthority: null } | { valueBearing: null } | { standard: null };
167
+ export interface BackupMetadata {
168
+ status: BackupStatus;
169
+ sha256: string;
170
+ backupId: string;
171
+ createdBy: Principal;
172
+ createdAtNs: bigint;
173
+ totalSize: bigint;
174
+ backupLabel: [] | [string];
175
+ backupType: BackupType;
176
+ dbType: string;
177
+ chunkCount: bigint;
178
+ parentBackupId: [] | [string];
179
+ }
180
+ export interface BackupRetentionReport {
181
+ maxBackups: bigint;
182
+ dbType: string;
183
+ prunedBackups: bigint;
184
+ }
185
+ export type BackupStatus = { Uploading: null } | { Failed: null } | { Finalized: null };
186
+ export type BackupType =
187
+ { PartialSnapshot: null } | { IncrementalDiff: null } | { FullSnapshot: null };
188
+ export interface BatchReadItem {
189
+ result: { Ok: MemoryFile } | { Err: Error };
190
+ path: string;
191
+ }
192
+ export interface BearerToken {
193
+ expiresAtNs: bigint;
194
+ status: BearerTokenStatus;
195
+ lastUsedNs: bigint;
196
+ permissions: AgentPermissions;
197
+ tokenId: string;
198
+ clientLabel: string;
199
+ issuedAtNs: bigint;
200
+ tokenHash: string;
201
+ issuedBy: Principal;
202
+ }
203
+ export type BearerTokenStatus = { Active: null } | { Revoked: null } | { Expired: null };
204
+ export interface CallerSignatureCount {
205
+ count: bigint;
206
+ role: Role;
207
+ root: [] | [Principal];
208
+ caller: Principal;
209
+ }
210
+ export interface CertifiedAuditHead {
211
+ total: bigint;
212
+ certificate: [] | [Uint8Array | number[]];
213
+ headHash: Uint8Array | number[];
214
+ size: bigint;
215
+ witness: [] | [Uint8Array | number[]];
216
+ }
217
+ export interface CheckpointPage {
218
+ firstAvailableSeq: bigint;
219
+ page: Page_15;
220
+ scannedThroughSeq: bigint;
221
+ }
222
+ export interface ChildAllowanceRow {
223
+ root: Principal;
224
+ remaining: bigint;
225
+ }
226
+ export interface ChildOpening {
227
+ attachCycles: bigint;
228
+ balance: bigint;
229
+ allowances: Array<ChildAllowanceRow>;
230
+ floorCycles: bigint;
231
+ }
232
+ export interface CondenseCheckpointRow {
233
+ by: Principal;
234
+ seq: bigint;
235
+ toSeq: bigint;
236
+ opsRoot: Uint8Array | number[];
237
+ atNs: bigint;
238
+ fromSeq: bigint;
239
+ headAtBoundary: Uint8Array | number[];
240
+ opCount: bigint;
241
+ }
242
+ export interface CondensePreview {
243
+ scannedFromSeq: bigint;
244
+ scanTruncated: boolean;
245
+ firstAvailableSeq: bigint;
246
+ unlocked: boolean;
247
+ totalEvents: bigint;
248
+ maxUnlockableToSeq: bigint;
249
+ bestUnfilteredReceipt: [] | [{ seq: bigint; toSeq: bigint; fromSeq: bigint }];
250
+ opCountInRange: bigint;
251
+ filteredReceiptsSeen: bigint;
252
+ coveringReceipt: [] | [{ seq: bigint; toSeq: bigint; fromSeq: bigint }];
253
+ proposedToSeq: bigint;
254
+ }
255
+ export interface CondenseResult {
256
+ seq: bigint;
257
+ toSeq: bigint;
258
+ opsRoot: Uint8Array | number[];
259
+ head: Uint8Array | number[];
260
+ fromSeq: bigint;
261
+ headAtBoundary: Uint8Array | number[];
262
+ newFirstAvailableSeq: bigint;
263
+ historyBytesDelta: bigint;
264
+ opCount: bigint;
265
+ }
266
+ export type ControlHandover =
267
+ { MovedByRegistry: null } | { NotHeldHere: null } | { MovedByEngram: null };
268
+ export interface CycleSnapshot {
269
+ seq: bigint;
270
+ source: { balance: null } | { self: null };
271
+ atNs: bigint;
272
+ cycles: bigint;
273
+ }
274
+ export interface Eip3009Authorization {
275
+ r: Uint8Array | number[];
276
+ s: Uint8Array | number[];
277
+ v: number;
278
+ to: string;
279
+ value: bigint;
280
+ from: string;
281
+ validAfter: bigint;
282
+ nonce: Uint8Array | number[];
283
+ validBefore: bigint;
284
+ }
285
+ export interface Eip712Registration {
286
+ encodeTypeString: string;
287
+ cooloffEndsAtNs: bigint;
288
+ typeId: Uint8Array | number[];
289
+ }
290
+ export interface Eip712SignatureOut {
291
+ r: Uint8Array | number[];
292
+ s: Uint8Array | number[];
293
+ v: number;
294
+ rendered: string;
295
+ digest: Uint8Array | number[];
296
+ }
297
+ export type Eip712Value =
298
+ | { string: string }
299
+ | { bool: boolean }
300
+ | { uint: bigint }
301
+ | { address: string }
302
+ | { fixedBytes: Uint8Array | number[] }
303
+ | { bytes: Uint8Array | number[] };
304
+ export interface Engram {
305
+ /**
306
+ * / ⟨0.16.0⟩ `about()` — the ONE public projection, replacing `status()` and absorbing `metrics()`.
307
+ * /
308
+ * / Two public projections of one canister was the L2.2 defect: both answered "what is this engram
309
+ * / like", disagreed about which counters they carried, and `status()` additionally masked two
310
+ * / fields behind an `authorized` flag whose own declaration admitted the problem — "a consumer
311
+ * / that must remember to check a sibling flag is one that will eventually forget."
312
+ * /
313
+ * / The fix is not a better flag. The gated fields MOVED (see `getOwnerConsole`), so there is no
314
+ * / masked field to forget and no flag to check. Reaching the gated record is the authorization.
315
+ * /
316
+ * / Ungated by design and marked for the L8 gate-grep.
317
+ * / PUBLIC: existence, shape, posture and day-floored activity. No principal, no balance, no
318
+ * / precise timestamp — nothing here identifies a person or reveals when they are at the keyboard.
319
+ */
320
+ about: ActorMethod<[], About>;
321
+ /**
322
+ * / The NEW key accepts the nomination the agent's current key (`agentKey`) made of it, and takes
323
+ * / over the agent's record: the same lasting identity, enrolment statement, invite and
324
+ * / permissions, today's spending and signature totals, and any spending limit the owner set for
325
+ * / that agent. From this message on, `agentKey` is not an agent of this engram and every call it
326
+ * / makes as one is refused. The registry is not called: it goes on naming the same open
327
+ * / engagement (`KeyReplacement`'s header says why and what a modified engram could do with it).
328
+ * /
329
+ * / ONE MESSAGE, NO AWAIT: every check, the move of the record and of each per-key total, and the
330
+ * / record entry happen together, so no call can fall between a check and the move, and no total
331
+ * / is ever held by both keys or by neither. Answers the record as the new key now holds it.
332
+ * /
333
+ * / WHO MAY CALL is decided by `KeyReplacement.accepted`: only the key a pending, unexpired
334
+ * / nomination names. That check compares the caller inside the module, where
335
+ * / test/key-replacement.test.mo runs it; this body names no roster gate, because the caller holds
336
+ * / no role here until the move.
337
+ */
338
+ acceptAgentKeyNomination: ActorMethod<[Principal], Result_70>;
339
+ /**
340
+ * / Consensus transform for the alert webhook outcall: collapse the response to status-only so
341
+ * / replicas agree regardless of response headers/body (we only care that the POST landed 2xx).
342
+ * /
343
+ * / PUBLIC: not a choice. The management canister invokes a transform on every replica as part of
344
+ * / the HTTP-outcall protocol, and that invocation carries no caller identity to gate on — a gate
345
+ * / here would refuse the only caller there is and break every alert this canister sends. Safe
346
+ * / because it is total and stateless: it reads its argument and returns, touching nothing.
347
+ */
348
+ actionAlertTransform: ActorMethod<
349
+ [{ context: Uint8Array | number[]; response: HttpRequestResult }],
350
+ HttpRequestResult
351
+ >;
352
+ /**
353
+ * / Register a typed-data shape as signable. Owner-only, freeze-gated (a registration is a grant
354
+ * / of FUTURE authority — a frozen engram must not be able to widen what it can sign), and the
355
+ * / shape is IMMUTABLE: any change mints a new typeId.
356
+ */
357
+ addEip712Type: ActorMethod<
358
+ [
359
+ {
360
+ primaryType: string;
361
+ canonicalTypeString: string;
362
+ domainName: string;
363
+ verifyingContract: string;
364
+ dailySignCap: bigint;
365
+ fields: Array<[string, string]>;
366
+ destinationFields: Array<string>;
367
+ authorityClass: { standingAuthority: null } | { valueBearing: null } | { standard: null };
368
+ chainId: bigint;
369
+ domainVersion: string;
370
+ ackIrrevocable: boolean;
371
+ },
372
+ ],
373
+ Result_69
374
+ >;
375
+ /**
376
+ * / Owner-managed destination allowlist (D7). Additions LOOSEN and wait 24h; removals TIGHTEN
377
+ * / and apply instantly — the ratified asymmetry, applied to the one mutable policy surface.
378
+ */
379
+ addEvmWithdrawDestination: ActorMethod<[string], Result_68>;
380
+ /**
381
+ * / ⟨0.16.0, L1⟩ THE ROLE-CONFLICT ARM, and why three refusals here are not the same refusal.
382
+ * /
383
+ * / This method had five distinct ways to say no through one `text`, and a caller could only tell
384
+ * / them apart by matching prose. They are now three different arms because they call for three
385
+ * / different responses: `#Invalid` means fix the argument and retry, `#Refused` means you are not
386
+ * / the owner and retrying changes nothing, and `#Conflict` means the request was well-formed and
387
+ * / permitted but this engram's state says no — the principal already holds an incompatible role,
388
+ * / or the roster is full. Only the last is worth an agent's time to resolve.
389
+ */
390
+ addGuardian: ActorMethod<[Principal, string, GuardianPermissions], Result_1>;
391
+ /**
392
+ * / Returns the write RECEIPT, not just the version.
393
+ * /
394
+ * / The receipt was always computed and then thrown away: MemoryRouter hands back
395
+ * / {seq; version; contentRoot; head}, the audit detail stringifies `seq=`/`head=` into prose, and
396
+ * / the caller got a bare Nat. So a writer could be told their write landed but not be given the
397
+ * / evidence it landed — they had to read the audit log back and parse a string to learn the head
398
+ * / their own write produced. `head` is the chain head AFTER this write; it transitively commits
399
+ * / to contentRoot, which is why the root is not repeated here (the same ruling that dropped
400
+ * / per-entry contentRoot from the audit entries).
401
+ * /
402
+ * / This is the half of a consumer request that costs nothing: the commitment ledger was still
403
+ * / "trust whoever runs the service" one hop from the proof — a third party can now be handed the receipt
404
+ * / directly by whoever wrote the content. A return-TYPE change cannot be absorbed by the client
405
+ * / subset rule, so it can only ride an interface break; this release is one.
406
+ */
407
+ appendMemory: ActorMethod<[string, Uint8Array | number[], [] | [MemorySource]], Result>;
408
+ /**
409
+ * / Replace the retained log prefix through `toSeq` with a single checkpoint.
410
+ * /
411
+ * / PREFIX-ONLY: there is no `fromSeq`, because the library made that unrepresentable rather than
412
+ * / merely checked — a condense always starts at the current floor. It refuses unless an
413
+ * / UNFILTERED export receipt already covers the whole range; call previewCondense first,
414
+ * / which reports how far your existing receipts reach.
415
+ * /
416
+ * / `historyBytesDelta` is SIGNED, and the sign is the point. A condense subtracts the dropped
417
+ * / entries' canonical bytes and adds the checkpoint's own, so condensing a short prefix of small
418
+ * / entries can leave the history meter HIGHER than it found it. The owner is told which happened
419
+ * / rather than left to assume the number went down.
420
+ * /
421
+ * / Gated on requireWritesNotPaused — unlike the export. This one destroys retained entries, which
422
+ * / is exactly what a guardian pause exists to hold. No action alert is raised: the operation is
423
+ * / owner-initiated, owner-only, and already chained into the audit log.
424
+ */
425
+ applyCondense: ActorMethod<[bigint], Result_67>;
426
+ /**
427
+ * / Owner-only: activate a guardian who has registered against an invite.
428
+ * /
429
+ * / Until this call the guardian is `#Pending` and can do NOTHING — registering is a claim, this
430
+ * / is the grant. That two-step is what stops a leaked invite code from producing a live guardian
431
+ * / on its own.
432
+ * /
433
+ * / `#Conflict("Guardian is already active")` when there is nothing to do — the refusal says the
434
+ * / state the caller asked for is the state that holds, rather than pretending it acted.
435
+ */
436
+ approveGuardian: ActorMethod<[Principal], Result_1>;
437
+ /**
438
+ * / Owner-only: approve one pending over-limit request, letting the agent retry the operation
439
+ * / its policy refused.
440
+ * /
441
+ * / ⚠ THE APPROVAL IS SINGLE-USE AND EXPIRES IN ONE HOUR. Approving does not perform the
442
+ * / operation and does not raise the policy — it opens a window. The agent must retry within
443
+ * / the hour, and the retry CONSUMES the approval (`#Used`); a second attempt needs a second
444
+ * / approval. Past the hour it becomes `#Expired` on first touch. Neither state is recoverable by
445
+ * / approving again — the owner approves a NEW request.
446
+ * / ⟨2026-09-29, review finding X-11⟩ One exception, made by the engram and not by the owner: when
447
+ * / the retry's signer FAILS, nothing was signed, so the approval goes back from `#Used` to
448
+ * / `#Approved` with its original expiry and an `approval.released` entry says so.
449
+ * /
450
+ * / ⚠ IT IS BOUND TO THE EXACT OPERATION THAT WAS REQUESTED, not to the agent. An approval
451
+ * / carries the operation, the amount and the binding it was raised for, and consuming it checks
452
+ * / all three — so approving a request does not grant the agent a general allowance for the
453
+ * / hour, and cannot be redirected at a different recipient or a larger sum.
454
+ * /
455
+ * / Refuses `#NotFound` for an unknown id, and `#Conflict` NAMING THE STATUS when the request is
456
+ * / no longer pending — already approved, denied or expired. The status is in the message because
457
+ * / "not pending" is the one refusal here an owner acts on differently depending on which it is.
458
+ */
459
+ approveRequest: ActorMethod<[string], Result_1>;
460
+ /**
461
+ * / Discard a backup started by `backupInit` and never finalized. The way out of a failed upload,
462
+ * / and the reason a stalled one need not occupy space indefinitely. Same gate as the rest of the
463
+ * / write half: owner, or an agent holding `canAppendMemory`.
464
+ */
465
+ backupAbort: ActorMethod<[string], Result_1>;
466
+ /**
467
+ * / Close a backup started by `backupInit` and mark it usable.
468
+ * /
469
+ * / ⚠ ONLY THE CREATOR MAY FINALIZE — `#Refused("Not the creator of this backup")`. An agent
470
+ * / cannot close an upload someone else began, so a half-finished backup belongs to whoever
471
+ * / started it.
472
+ * /
473
+ * / Refuses with `#Conflict` when the backup is already finalized, when it is marked failed, and
474
+ * / when it holds ZERO chunks or zero total size — an empty backup is refused rather than recorded
475
+ * / as a success, which is the difference between "no backup" and "a backup of nothing".
476
+ * /
477
+ * / It does NOT verify the `sha256` declared at init; see that method for what the digest is and
478
+ * / is not.
479
+ */
480
+ backupFinalize: ActorMethod<[string], Result_1>;
481
+ /**
482
+ * / Begin a chunked backup upload. Returns the `backupId` every later call in the sequence needs.
483
+ * /
484
+ * / **THE SEQUENCE**, which no individual signature here conveys:
485
+ * / `backupInit` → `backupPushChunk` × N → `backupFinalize`, or `backupAbort` to discard. A backup
486
+ * / that is never finalized is not a backup; `backupFinalize` refuses one with zero chunks or zero
487
+ * / total size rather than recording an empty success.
488
+ * /
489
+ * / ⚠ THE `sha256` IS YOUR DECLARATION, NOT THIS CANISTER'S FINDING. It is taken here, before any
490
+ * / bytes arrive, stored with the metadata and carried through finalize UNCHANGED — verified at
491
+ * / the site 2026-08-21: `Backup.finalizeBackup` checks existence, creator, state and non-emptiness
492
+ * / and does NOT recompute or compare a digest. So it is a commitment a restorer can check the
493
+ * / bytes against LATER, and it is not evidence the bytes match. Treating it as a canister-verified
494
+ * / hash is the misreading to avoid — and it is an easy one to reach, because the REGISTRY's
495
+ * / chunked upload (`engramWasmInit`/`PushChunk`/`Finalize`) has the same shape and DOES verify:
496
+ * / it hashes the assembled bytes and refuses on mismatch. Same protocol, opposite semantics.
497
+ * /
498
+ * / **TWO DIFFERENT PERMISSIONS GUARD THE TWO HALVES.** Writing (init, push, finalize, abort) is
499
+ * / owner-or-agent and an AGENT additionally needs `canAppendMemory`; reading
500
+ * / (`backupPullChunk`) needs `read_backup`. An agent can therefore be able to upload a backup
501
+ * / and unable to download one, or the reverse, which is the point of splitting them.
502
+ * /
503
+ * / The write half also refuses while writes are PAUSED.
504
+ */
505
+ backupInit: ActorMethod<[string, BackupType, [] | [string], string, [] | [string]], Result_43>;
506
+ /**
507
+ * / Read one chunk of a finalized backup, by index.
508
+ * /
509
+ * / ⚠ GATED ON `read_backup`, which is NOT the permission the upload half uses — that one is
510
+ * / `canAppendMemory`. Holding one says nothing about the other, deliberately: taking a backup and
511
+ * / carrying it away are different authorities.
512
+ */
513
+ backupPullChunk: ActorMethod<[string, bigint], Result_59>;
514
+ backupPushChunk: ActorMethod<[string, bigint, Uint8Array | number[]], Result_1>;
515
+ /**
516
+ * / The OWNER cancels an agent's pending key nomination; the agent keeps its current key. Refused
517
+ * / by name when the agent is unknown or has nothing pending — never a silent success.
518
+ */
519
+ cancelAgentKeyNomination: ActorMethod<[Principal], Result_1>;
520
+ /**
521
+ * / Close a session the caller paid for: settle what was consumed, refund the remainder.
522
+ * /
523
+ * / PAYER-ONLY, enforced inside the gateway. This is the exit that did not exist — `endSession`
524
+ * / and `forceCloseSession` were on the MARKET, which is withheld, and whose escrow subaccount is
525
+ * / under a different principal entirely, so its close could never have reached these funds.
526
+ */
527
+ closeSession: ActorMethod<[string], Result_1>;
528
+ /**
529
+ * / Convert the engram's OWN earned ckUSDC/ckUSDT into its OWN cycles, via the cashier — the
530
+ * / engram-self top-up path. Owner-only; per-call cap + cooldown (irreversible); NOT freeze-gated
531
+ * / (infrastructure funding). Flow: read the engram's deposit address on the cashier, move the
532
+ * / engram's tokens there, then have the cashier convert — the cashier self-authorizes because the
533
+ * / caller (this engram) is a registered active engram (registry isRegisteredActiveEngram seam).
534
+ * / (The owner-funded path lives entirely in the frontend: owner → cashier deposit → topUp.)
535
+ * / ⟨0.16.0, L4 — `token : Text` KEPT, deliberately, and this note exists so the sweep that finds
536
+ * / it does not re-litigate it.⟩
537
+ * /
538
+ * / `ownerWithdraw` and the market's `recoverEscrow` both took `Wire.TokenAmount` because they
539
+ * / accept ICP (e8s) BESIDE the stablecoins (e6) — mixed decimals behind one number is a real
540
+ * / hundred-fold error. This method accepts ckUSDC and ckUSDT only. Both are e6, so there is no
541
+ * / unit to get wrong, and the census (row 258) rules the pair as `(token, amountE6)`.
542
+ * /
543
+ * / `Wire.TokenAmount` would be actively WORSE here: its `#Icp` arm is a token this path cannot
544
+ * / convert, so the type would make an unacceptable value REPRESENTABLE and hand back a runtime
545
+ * / rejection anyway — losing the one property the variant is for while gaining a wider type.
546
+ * /
547
+ * / ⟨2026-10-02⟩ The second parameter is NAMED `amountE6` now, as the census row above rules the
548
+ * / pair — e6 base units of the token named first. A name only: Candid passes arguments by
549
+ * / position, so nothing on the wire moved.
550
+ */
551
+ convertEarningsToCycles: ActorMethod<[string, bigint], Result_8>;
552
+ /**
553
+ * / Owner-only: mint a single-use invite code an agent redeems with `pairAgent`.
554
+ * /
555
+ * / ⚠ READ THIS BEFORE INVITING SOMEONE BACK. Pairing is ONE-SHOT PER PRINCIPAL on
556
+ * / this engram: `pairAgent` refuses ANY caller that already holds a record — `#Active`,
557
+ * / `#Revoked` or `#Resigned` alike — so a principal you have revoked can NEVER redeem another
558
+ * / invite, however many you mint. That is deliberate, because `revokeAgent` is a soft status
559
+ * / change and a revoked key talking its way back in would undo it. The remedy is a DIFFERENT
560
+ * / WALLET; the only thing that clears the record is `resetEngram`, which severs everything else
561
+ * / too.
562
+ * /
563
+ * / Two caps, each refusing with `#Conflict` and naming its own limit: concurrent ACTIVE agents
564
+ * / (multi-agent owners legitimately need several — a connector host plus a coding agent), and
565
+ * / concurrent unexpired INVITES. Neither is a rate limit; both are ceilings you clear by revoking
566
+ * / or by letting invites lapse.
567
+ * /
568
+ * / A principal that is already a GUARDIAN cannot become an agent — a guardian is an
569
+ * / independent check on agents, so one wallet must not hold both.
570
+ */
571
+ createAgentInvite: ActorMethod<[string, AgentPermissions], Result_43>;
572
+ /**
573
+ * / Owner-only: mint an invite for a GUARDIAN — an independent check on agents, not a
574
+ * / co-owner and not a recovery agent.
575
+ * /
576
+ * / ⚠ WHAT A GUARDIAN CAN DO IS EXACTLY THREE THINGS, all of them BRAKES: revoke agents,
577
+ * / freeze payments, pause writes. That is the whole permission set (`GuardianPermissions`), and
578
+ * / the three flags are FROZEN — any future permission arrives as a scope string instead.
579
+ * /
580
+ * / ⚠ WHAT A GUARDIAN CANNOT DO, said plainly because the word invites the opposite reading: they
581
+ * / cannot read memory, cannot move money, cannot transfer ownership, and **cannot recover a lost
582
+ * / owner key**. A guardian is not a recovery mechanism. An owner appointing one against the day
583
+ * / they lose access is appointing the wrong thing.
584
+ * /
585
+ * / Two steps, and the invite is only the first: the invitee registers, which leaves them
586
+ * / `#Pending` and INERT, and `approveGuardian` is what makes them active. A guardian who has
587
+ * / registered but not been approved can do none of the three.
588
+ * /
589
+ * / ⚠ AN AGENT CANNOT BECOME A GUARDIAN, and the refusal lands at REGISTRATION rather than
590
+ * / here: this call will happily mint an invite for a principal that already holds an agent
591
+ * / record, and `registerGuardian` then refuses it with "An agent cannot also be a guardian".
592
+ * / So an invite that fails to redeem for that reason is not a bad code. The rule exists because
593
+ * / a check must be independent of the thing it checks.
594
+ */
595
+ createGuardianInvite: ActorMethod<[string, GuardianPermissions], Result_43>;
596
+ /**
597
+ * / OWNER-ONLY deletion of a stored backup.
598
+ * /
599
+ * / ⚠ NOT THE SAME GATE AS THE REST OF THE FAMILY, and the asymmetry is deliberate: `backupInit`,
600
+ * / `backupPushChunk`, `backupFinalize` and `backupAbort` accept an agent holding
601
+ * / `canAppendMemory`, and `backupPullChunk` accepts one holding `read_backup`. Only the OWNER may
602
+ * / delete. So an agent can take backups and carry them away and cannot destroy one —
603
+ * / creating is delegable, destroying is not.
604
+ * /
605
+ * / `backupAbort` is the agent's way out of a failed UPLOAD; it discards something never
606
+ * / finalized. This removes a finished backup, which is a different act on a different object.
607
+ */
608
+ deleteBackup: ActorMethod<[string], Result_1>;
609
+ /**
610
+ * / ⟨0.16.0, census §10 item 16⟩ RETURNS A REAL RECEIPT, not `R<()>`. The receipt was already
611
+ * / being computed and written into the audit line — `receiptSuffix(r)` — and then discarded, so
612
+ * / a caller could not cite the seq its own delete produced and had to go looking for it in a log
613
+ * / it may not be allowed to read. A delete is an EVENT on the chain; an event that will not tell
614
+ * / you where it landed is evidence nobody can point at. Same projection as writeMemory.
615
+ */
616
+ deleteMemoryFile: ActorMethod<[string], Result>;
617
+ /**
618
+ * / Owner-only: deny one pending over-limit request, with a `reason` the agent can read.
619
+ * /
620
+ * / The reason is stored on the request rather than discarded, which is the point of taking it —
621
+ * / an agent told only "denied" retries, and one told why can adapt or stop asking. It is the
622
+ * / owner's message to whoever raised the request, not an audit-only field.
623
+ * /
624
+ * / Terminal: a denied request cannot be approved afterwards. Like `approveRequest` it refuses
625
+ * / `#NotFound` for an unknown id and `#Conflict` when the request is no longer pending, and it
626
+ * / does not change the policy — the next request over the same limit will be raised again.
627
+ */
628
+ denyRequest: ActorMethod<[string, string], Result_1>;
629
+ /**
630
+ * / Force the tECDSA derivation and return the address.
631
+ * /
632
+ * / It exists because the gateway's own derivation fires from a timer that is lazy on some
633
+ * / replicas, and until it lands the EVM quote advertises the `0x0` fallback and settle fails
634
+ * / closed — a live money surface quoting an address that cannot receive.
635
+ * /
636
+ * / ⟨0.16.0, B-2⟩ Derivation now comes from `EvmIdentity`, and the return type carries the
637
+ * / outcome: this used to answer `""` on failure, which is a Text a caller can and did paste into
638
+ * / a payment flow. An empty string is not an address, and saying so is the difference between a
639
+ * / failed derivation and an address of nothing.
640
+ * /
641
+ * / ⚠ TRANSITIONAL: it also primes the ic402 gate, because the gate still settles commerce on this
642
+ * / canister until those 47 methods move. That second call disappears with them — it is listed in
643
+ * / the move order in the spec's B-2 addendum, not left for someone to find.
644
+ * /
645
+ * / PUBLIC: it inherits `getEvmAddress`'s gate rather than choosing one, and could not usefully be
646
+ * / narrower — it exists so a caller can make the derivation happen BEFORE a payment flow, and the
647
+ * / derivation itself is ungated. Idempotent and bounded to the same one-derivation-per-lifetime
648
+ * / work, so an anonymous caller can cause it once and no more.
649
+ * / ⟨L7⟩ UPDATE, NOT QUERY, and this one does not merely await — it WRITES. The body awaits
650
+ * / `EvmIdentity.deriveAddress` (the management canister's `ecdsa_public_key`) and
651
+ * / `gate.deriveEvmRecipientAt` ⟨renamed 2026-09-22 with the path⟩, then caches the result in `evmAddressCache`. So a query is
652
+ * / impossible twice over: it could not await the derivation, and it could not keep the answer.
653
+ * / Named `ensure*` rather than `get*` for that reason — the write is the point, and a read verb
654
+ * / would have promised a cheapness this cannot deliver.
655
+ * /
656
+ * / ⟨Marker added 2026-08-23; the census row said "L7 mark added per review" and no mark was at
657
+ * / the site.⟩
658
+ */
659
+ ensureEvmReady: ActorMethod<[], Result_43>;
660
+ /**
661
+ * / Record that log entries [fromSeq, toSeq] were served, and return the root that proves it.
662
+ * /
663
+ * / This is the receipt ledgerfs Q2 requires before any of those entries may be condensed away.
664
+ * / The canister cannot know the owner KEPT the bytes it served — it can only prove they were
665
+ * / SERVED — and `opsRoot` is what makes a kept copy verifiable forever afterwards. Keep it with
666
+ * / the archive; without it the download is just bytes.
667
+ * /
668
+ * / NOT gated on requireWritesNotPaused, deliberately. A guardian pause is an emergency brake on
669
+ * / changing the record; an export changes nothing about the files and only appends its own
670
+ * / attestation. Trapping the owner's own data behind the brake would make the pause a hostage
671
+ * / situation rather than a safety measure. It IS gated on requireMemoryAttached: a store that
672
+ * / failed its integrity check must not attest anything it cannot vouch for.
673
+ */
674
+ exportMemoryRange: ActorMethod<[bigint, bigint, [] | [Principal]], Result_66>;
675
+ /**
676
+ * / ⟨0.16.0, L2.2 — renamed from `guardianFreezePayments`⟩ The prefix LIED about who may call it.
677
+ * / The gate is `requireOwnerOrGuardian`, and an owner freezing their own payments is the ordinary
678
+ * / case — the guardian is the exceptional one. A name that says otherwise sends an owner looking
679
+ * / for a method that does not exist. `unfreezePayments`, its owner-only inverse, never carried the
680
+ * / prefix, so the pair read as unrelated.
681
+ * /
682
+ * / WHAT THE FREEZE ACTUALLY COVERS ⟨enumerated 2026-08-21 from the eight `requirePaymentsNotFrozen`
683
+ * / call sites, because it was written down nowhere and had to be re-derived to be trusted⟩:
684
+ * /
685
+ * / · EVERY SIGNING PATH, which is the point of the brake. `signX402Payment` and
686
+ * / `sysSignX402Payment` through `x402SignFor`; `signEip712` and `sysSignEip712` through
687
+ * / `eip712SignFor`; `signEngramRegistration` directly. ⟨The two helpers are why a grep of an
688
+ * / individual method's body finds nothing — the check is one level down.⟩
689
+ * / · `addEip712Type` and `addEvmWithdrawDestination` — pre-staging for a later payout is the
690
+ * / thing a brake most needs to stop, so the destination list is frozen along with the signing.
691
+ * / · `sessionReadMemory` and `sessionAppendMemory` — the paid-memory rail, money coming IN.
692
+ * /
693
+ * / AND WHAT IT DELIBERATELY DOES NOT, stated so the absence is not read as an oversight:
694
+ * /
695
+ * / · `convertEarningsToCycles` — the owner's OWN earnings becoming their OWN engram's fuel. A
696
+ * / frozen engram still burns cycles, so freezing this would let a brake starve the thing it
697
+ * / is protecting. Owner-only, capped per call, and it moves nothing outward.
698
+ * / · `approveRequest` — an approval is not a spend. The spend it authorises goes through
699
+ * / `x402SignFor`, which IS frozen, so an approval granted during a freeze simply waits.
700
+ * / · `transferOwnership` — ownership is not a payment, and a guardian's PAYMENTS brake is not
701
+ * / a veto on who owns the engram.
702
+ * /
703
+ * / ⚠ The three exclusions are a reading of intent, not a ruling: no declaration stated the scope
704
+ * / before this one. If any of them is wrong, this comment is where the argument should happen.
705
+ */
706
+ freezePayments: ActorMethod<[], Result_1>;
707
+ /**
708
+ * / Delivery status + config readback. Owner-only (the URL is a secret).
709
+ */
710
+ getActionAlertStatus: ActorMethod<[], Result_57>;
711
+ /**
712
+ * / Agents need to know what they may revise, so they can read it too. Whole-value config, same
713
+ * / carve-out as getProtectedPaths — and kept a SEPARATE method from it deliberately (L2.2): a
714
+ * / protected path and a revisable path are opposite grants, and one accessor for both would be a
715
+ * / name that lies about which power it reports.
716
+ * /
717
+ * / Refusal reason preserved from the trap: a grant is a power, and its absence and its
718
+ * / concealment are different facts.
719
+ */
720
+ getAgentRevisablePaths: ActorMethod<[], Result_53>;
721
+ /**
722
+ * / OWNER-ONLY: every engagement's seat weeks on this engram, with the agent's root — the day it
723
+ * / paired, the days of its first and last payment signature, a 64-week map whose bit 0 is the week
724
+ * / of the last one, and how many were produced. Never an amount, a recipient or a nonce.
725
+ * /
726
+ * / WHY THE OWNER ALWAYS READS IT: these are the rows the metrics reader the registry designated may
727
+ * / read (`sysGetAgentSeatWeeks`), and an owner deciding whether to leave that read on must be able
728
+ * / to see exactly what it is handed. The reader's rows are these rows without the root, in the same
729
+ * / order. Anyone else is refused by name (`#Refused getAgentSeatWeeks: …`), never answered with an
730
+ * / empty page. Paged; `total` is every engagement ever paired here (a reset keeps the rows).
731
+ * / Two rows can name one root: an agent paired again after it left is a second engagement.
732
+ */
733
+ getAgentSeatWeeks: ActorMethod<[bigint, bigint], Result_64>;
734
+ /**
735
+ * / Owner: everything written into this engram by someone other than the owner since the last
736
+ * / markAgentWritesReviewed() — agent appends/revisions AND paid-session appends (see
737
+ * / qualifiesForReview for why those two families are recognised differently).
738
+ * / `capped=true` means exactly 200 rows were returned and MORE unreviewed writes exist beyond
739
+ * / them — the UI must page (markAgentWritesReviewed(?lastShownId)) and must NOT present 200
740
+ * / as a total. `earliest` discloses ring eviction — if cursor < earliest, entries between them
741
+ * / aged out of the ring (the CHAIN still proves total count; this view can't show their bodies).
742
+ */
743
+ getAgentWriteReview: ActorMethod<[], Result_63>;
744
+ /**
745
+ * / Why anchoring is or is not advancing. PUBLIC: ungated on purpose — detecting a stalled
746
+ * / engram is the point, a gated read would fail-to-empty and hand a third party fabricated zeros,
747
+ * / and none of these fields is a secret — `total` is already public via getCertifiedAuditHead.
748
+ * / See the field comments above for how to read the combinations.
749
+ */
750
+ getAnchorPushStatus: ActorMethod<[], AnchorPushStatus>;
751
+ /**
752
+ * / The plain chain head — size and hash, world-readable, no certificate.
753
+ * /
754
+ * / ⟨0.16.0, census `keep (NEW)`⟩ It was specced and never built. `Wire.AuditHead`'s own
755
+ * / declaration says why it matters: heads exist TO BE COMPARED (L8), a head nobody can read
756
+ * / witnesses nothing, and the registry and cashier already served exactly this shape — so the
757
+ * / engram, "the canister that IS the evidence product", was the one chain a verifier could not
758
+ * / ask for a head without also asking for a certificate it may not want.
759
+ * /
760
+ * / PUBLIC: bare, and it cannot refuse — a chain head discloses nothing about content or callers,
761
+ * / and gating it would make the comparison it exists for depend on permission. `getCertifiedAuditHead`
762
+ * / below serves the same head WITH the subnet certificate for a caller that needs to verify it
763
+ * / was signed rather than asserted.
764
+ */
765
+ getAuditHead: ActorMethod<[], AuditHead>;
766
+ getBackupMetadata: ActorMethod<[string], Result_62>;
767
+ /**
768
+ * / The cashier this engram recognises as its rent biller — `null` until the registry pushes one.
769
+ * /
770
+ * / PUBLIC: a payer about to send money needs to know which cashier this engram will accept credit
771
+ * / from, BEFORE sending it — paying a cashier this engram does not recognise collects funds that
772
+ * / never become rent. The registry publishes the same fact as `getRentBiller`; publishing it here
773
+ * / too is what lets the two be COMPARED, which is the only way to catch a mismatch.
774
+ */
775
+ getBillerId: ActorMethod<[], [] | [Principal]>;
776
+ /**
777
+ * / ⟨0.16.0, L9/L10 — census row⟩ `Wire.CertifiedAuditHead`, not an anonymous record. The
778
+ * / registry, market and cashier already served the shared type; the engram — the canister that
779
+ * / IS the evidence product — was the one chain still answering in a shape of its own, missing
780
+ * / `witness` entirely. One certified-head shape on every chain is the point: a verifier that can
781
+ * / read three of them and not the fourth has to special-case the one that matters most.
782
+ * /
783
+ * / `witness = null` is the honest answer here and is NOT the same as an empty proof. This engram
784
+ * / certifies its head via `CertifiedData` but keeps no witness tree, so there is no reveal to
785
+ * / encode; `?Blob` lets it say "I do not serve a proof" rather than fabricate one.
786
+ * /
787
+ * / PUBLIC: the certificate is the point — it lets a stranger verify against the NNS root key
788
+ * / instead of trusting this replica, and a proof that requires a role to fetch rests on exactly
789
+ * / the authority it was introduced to remove.
790
+ */
791
+ getCertifiedAuditHead: ActorMethod<[], CertifiedAuditHead>;
792
+ /**
793
+ * / The allowance of the agent holding `agentPrincipal`: its lasting key and the openings left.
794
+ * / Readable by the owner and by that agent's own key — refused loudly to anyone else, never a zero
795
+ * / (a zero would be a claim about another owner's grant).
796
+ * /
797
+ * / ⟨2026-10-01, review F2⟩ A QUERY, so the refusal is deliberately NOT written to the denial log: a
798
+ * / query's state writes are discarded when it returns, and the `denied` call first written here
799
+ * / recorded nothing while reading as if it did. The refusal is loud in the reply instead. WHAT
800
+ * / WOULD MAKE THIS WRONG: a reason to record who asked — then this becomes an update that says so.
801
+ */
802
+ getChildAllowance: ActorMethod<[Principal], Result_61>;
803
+ /**
804
+ * / Owner-only, Billing-class: what opening an engram costs this engram, the balance below which an
805
+ * / agent's request is refused, the balance now, and every agent's allowance. The console's cost
806
+ * / sentence reads it. Cycles are owner-class information, as on the owner's console read.
807
+ */
808
+ getChildOpening: ActorMethod<[], Result_60>;
809
+ /**
810
+ * / Derive the shared memory-encryption key, encrypted under the caller's transport
811
+ * / public key. Gated to owner + read-agents (the same principals allowed to read
812
+ * / memory). The client decrypts it locally with its transport secret key.
813
+ * / ⟨0.16.0⟩ THE FOLD: `epoch` is now an optional argument here, and the separate
814
+ * / `getEncryptedMemoryKeyForEpoch` is gone. Two methods differing only by whether one parameter
815
+ * / is present is what an optional argument is for, and the split forced a client to decide which
816
+ * / to call before it knew whether it needed rotation.
817
+ * /
818
+ * / `null` means CURRENT — not epoch 0. Those coincide today (nothing increments the epoch yet)
819
+ * / and will not after the first rotation, which is exactly when a caller that meant "the key that
820
+ * / seals my memory now" must not silently receive a superseded one. `?0` still names epoch 0
821
+ * / explicitly for a client rebuilding an old cache entry.
822
+ * /
823
+ * / Refusing a FUTURE epoch is not a bounds check, it is the rotation invariant: pre-deriving a
824
+ * / key for an epoch nobody has reached would make rotating to it meaningless.
825
+ * /
826
+ * / Also converted off the lowercase `#ok/#err` dialect (L5) — that spelling arrived from ic402
827
+ * / and had no business on a vetKD path, which touches nothing of ic402's.
828
+ * /
829
+ * / ⟨L7⟩ UPDATE, NOT QUERY, and this is the system call that forces it: the body awaits
830
+ * / `VetKeys.ManagementCanister.vetKdDeriveKey`. A query cannot await, so the round trip is the
831
+ * / cost. Stated here because L7 requires the reason be readable from the interface rather than
832
+ * / inferred by opening the body — which is exactly what had to happen to write this line.
833
+ */
834
+ getEncryptedMemoryKey: ActorMethod<[[] | [bigint], Uint8Array | number[]], Result_59>;
835
+ /**
836
+ * / ⟨0.16.0, owner ruling 2026-08-20 — option (a)⟩ `x402Support` REPORTS THE RAIL, not a constant.
837
+ * /
838
+ * / The card's config hardcodes `x402Support = true`, answering a buyer's question with a fact
839
+ * / about the software rather than about THIS engram. B1 moved the 402 challenge machinery to the
840
+ * / market; the one x402-payable rail the engram kept is `sessionReadMemory`, gated by
841
+ * / `paidMemoryReadEnabled`, which DEFAULTS TO FALSE. So a discovering agent was told this engram
842
+ * / takes x402 payments while every paid read on a default engram is refused with "the owner has
843
+ * / not opened the monetized read rail". Ruled (a) over keeping `true` to mean "can PARTICIPATE in
844
+ * / x402, including as a payer" — defensible, but not what a service card says to a buyer.
845
+ * /
846
+ * / Overridden HERE rather than at the config because the card is built once as a `public let`
847
+ * / while the flag is runtime state, and `getCard()` belongs to the VENDORED ic402 module, which
848
+ * / is not ours to edit.
849
+ * /
850
+ * / ⚠ `signEngramRegistration` also reads `getCard()` and is deliberately NOT changed. It signs an
851
+ * / ERC-8004 registration for on-chain publication — a point-in-time attestation nobody can
852
+ * / re-sign every time an owner opens or closes the rail. Whether a signed record should carry
853
+ * / mutable operational state at all is a different decision, it is signing-adjacent, and the
854
+ * / ruling did not reach it. Filed, not folded in.
855
+ * /
856
+ * / PUBLIC: an agent card is a DISCOVERY document — its entire function is to tell a party that
857
+ * / has never met this engram what it is and how to transact with it. A card behind a gate cannot
858
+ * / be discovered, and the ERC-8004 ecosystem it participates in assumes an open read.
859
+ */
860
+ getEngramCard: ActorMethod<[], AgentCard>;
861
+ /**
862
+ * / PUBLIC: the engram's permanent spawn ordinal — a provable, non-sensitive fact. It identifies a
863
+ * / canister, never a person.
864
+ * / null = spawned before numbering existed; the owner can backfill via syncEngramNumber().
865
+ */
866
+ getEngramNumber: ActorMethod<[], [] | [bigint]>;
867
+ /**
868
+ * / Re-pointed at `EvmIdentity` (B-2): custody derivation no longer routes through the ic402
869
+ * / Gateway, which is leaving for the market canister. Behaviour is unchanged for a caller — same
870
+ * / address, same tECDSA key — but the engram no longer needs a marketplace to know its own
871
+ * / address, which is the whole point of the split.
872
+ * /
873
+ * / ⟨2026-08-21⟩ DO NOT FOLD THIS WITH `getEvmSignerAddress`. The 0.16.0 census carried the fold
874
+ * / as an open item, conditional on "if the derivation is identical". It is not, and the condition
875
+ * / is decidable here rather than by reading either comment:
876
+ * /
877
+ * / this method EvmIdentity.deriveAddress -> derivation_path = []
878
+ * / the signer eip712PublicKey -> derivation_path = ["eip712"]
879
+ * /
880
+ * / ⟨CORRECTED 2026-09-22 — the two paths above are what the code passed until KEY-PATHS §4 step 5;
881
+ * / the table is kept because the ARGUMENT it makes is unchanged and is the reason the fold is
882
+ * / still refused.⟩ The signer now reads `KeyPaths.EIP712` = `["engramx","eip712","secp256k1","v1"]`
883
+ * / and this method still derives at the empty path, because `pay` is the one row the genesis could
884
+ * / not move — ic402 2.15.0 parameterises `EvmSigner` but not `Gateway.deriveEvmRecipient`,
885
+ * / `EvmSender` or `Identity`, and moving the signer without them would split receiving from
886
+ * / spending. The paths are still DIFFERENT, which is the whole of the argument below, and they get
887
+ * / further apart at the genesis rather than closer.
888
+ * /
889
+ * / ⟨SHIPPED 2026-09-22, ic402 2.16.0 — the table is now BOTH rows labelled, and the argument is
890
+ * / unchanged, which is the point of keeping every version of it here:
891
+ * /
892
+ * / this method EvmIdentity.deriveAddress -> KeyPaths.PAY = ["engramx","pay","secp256k1","v1"]
893
+ * / the signer eip712PublicKey -> KeyPaths.EIP712 = ["engramx","eip712","secp256k1","v1"]
894
+ * /
895
+ * / Two paths, one master key, therefore two addresses — exactly as when one of them was `[]`.
896
+ * / The fold stays refused for the reason below, not because one side happened to be a default.
897
+ * / What changed upstream is that `Gateway`, `EvmSender` and `Identity` all take a path now, so
898
+ * / the payment identity could move as ONE thing: this derivation, the gateway's inbound
899
+ * / recipient and outbound sender, and `Payments.evmSigner`. The genesis install derives them.⟩
900
+ * /
901
+ * / Same master key and curve, different paths, therefore different public keys and DIFFERENT
902
+ * / ADDRESSES — that is what a derivation path is for. The difference is also deliberate and
903
+ * / security-bearing, not incidental: the signer key is declared "outbound-only, N=1, never the
904
+ * / payment path — this key must never be able to move ic402 pool funds", so merging the two
905
+ * / would hand the signing surface the payment key. `getEvmSignerAddress` carries the warning
906
+ * / from its side ("the payment key's address is NOT this one, by design"); this is the other
907
+ * / side, because a fold is proposed by whoever reads either declaration first.
908
+ * /
909
+ * / The gates differ too, which a fold would also have to collapse: this method is UNGATED (any
910
+ * / caller may cause the derivation) and `getEvmSignerAddress` is owner-only.
911
+ * /
912
+ * / PUBLIC: an address is a destination, not a capability — publishing it lets anyone PAY this
913
+ * / engram and lets nobody spend from it. It has to be readable by a stranger because a stranger
914
+ * / is exactly who needs it. The write it causes is bounded to one derivation and one
915
+ * / set-once custody stamp per engram lifetime, which is what keeps "any caller may cause it"
916
+ * / safe rather than merely permitted.
917
+ * / ⟨L7⟩ UPDATE, NOT QUERY, and this is the system call that forces it: the body awaits
918
+ * / `EvmIdentity.deriveAddress`, which reaches the management canister's `ecdsa_public_key`. A
919
+ * / query cannot await it.
920
+ * /
921
+ * / ⟨Marker added 2026-08-23; the census row already said "L7 marked (ecdsa_public_key)" and the
922
+ * / site did not carry the mark. Same `public func` form as its two neighbours above.⟩
923
+ * /
924
+ * / ⟨2026-09-28⟩ THE REPLY IS A RECORD, `Types.EvmAddresses` — the payment address (`pay`, what this
925
+ * / method returned alone until then) and the address that signs the engram's own registrations
926
+ * / (`engramRegistration`). The owner decided that date to publish the registration address as a new
927
+ * / field on an existing address reply, not as a new method; nothing served it before, so an
928
+ * / agent could not read the address whose nonce `signEngramRegistration` needs and whose ETH
929
+ * / pays its gas. The registration address is read FROM THE SIGNER ITSELF
930
+ * / (`engramRegSigner.getEvmAddress`), not re-derived beside it, so the published address is by
931
+ * / construction the one the signatures come from. It is cached inside that signer object; the
932
+ * / cache is not stable, so the first call after an upgrade re-derives it once — the same one
933
+ * / public-key read, bounded, that the payment branch does on a null cache.
934
+ * /
935
+ * / It refuses rather than half-answers: if either address cannot be derived the reply is
936
+ * / `#Err`, never a record carrying an empty string (ic402's `getEvmAddress` answers `""` on a
937
+ * / failed derivation — that is fail-to-empty on a money surface, and it stops here).
938
+ */
939
+ getEvmAddress: ActorMethod<[], Result_58>;
940
+ /**
941
+ * / The owner's OWN EVM address, if they registered one — distinct from `getEvmAddress`, which is
942
+ * / the address this canister derives for itself.
943
+ * /
944
+ * / PUBLIC: an address is a public identifier on every chain it exists on; it is a destination,
945
+ * / not a capability, and knowing it confers nothing. `null` means the owner registered none,
946
+ * / which a payer needs to be able to tell from an address they failed to read.
947
+ */
948
+ getEvmOwnerAddress: ActorMethod<[], [] | [string]>;
949
+ /**
950
+ * / D1 ships with this: the address of the DEDICATED signing key. Without it the owner funds the
951
+ * / wrong address — the payment key's address is NOT this one, by design.
952
+ * /
953
+ * / ⟨L7⟩ UPDATE, NOT QUERY, and this is the system call that forces it: `eip712PublicKey()` awaits
954
+ * / the management canister's `ecdsa_public_key`. A query cannot await, so the round-trip is the
955
+ * / cost — stated here because L7 requires the reason be readable from the interface rather than
956
+ * / inferred by opening the body.
957
+ */
958
+ getEvmSignerAddress: ActorMethod<[], Result_43>;
959
+ /**
960
+ * / PUBLIC: where this chain begins, for the stranger deciding whether to trust it.
961
+ * /
962
+ * / The fourth of the four evidence methods (`getAuditHead`, `getCertifiedAuditHead`,
963
+ * / `listAuditEntries`, this) that every chain canister now serves in the same shape. Ungated for
964
+ * / the same reason the head is: a verifier who must ask permission to learn where a chain starts
965
+ * / cannot verify it, and nothing here identifies anybody.
966
+ */
967
+ getGenesisNote: ActorMethod<[], GenesisNote>;
968
+ /**
969
+ * / A guardian's own channel status (their URL is their secret — each guardian sees only theirs).
970
+ */
971
+ getGuardianAlertStatus: ActorMethod<[], Result_57>;
972
+ /**
973
+ * / The market this engram will accept signing requests from — `null` until the registry pushes
974
+ * / one at spawn, which is why `requireMarket` refuses fleet-wide today.
975
+ * /
976
+ * / PUBLIC: this is the whole of what stands between a stranger and this engram's signing key. A
977
+ * / counterparty evaluating an engram's market claim has to be able to read which market it is
978
+ * / pinned to, and `null` — "pinned to nobody, so it signs for nobody" — is the most important
979
+ * / answer it can give.
980
+ */
981
+ getMarketId: ActorMethod<[], [] | [Principal]>;
982
+ /**
983
+ * / FD, the one coordinated interface break: history no longer carries per-version CONTENT.
984
+ * /
985
+ * / The legacy shape returned a full snapshot of every version, which is what made history cost
986
+ * / O(total bytes ever written) and forced a per-version truncation cap that silently mangled
987
+ * / large files. What a reader gets now is the COMMITMENT — size and content root per version —
988
+ * / and content is read per version through readMemoryBytes, verified as it is served.
989
+ * /
990
+ * / Two deliberate shape changes beyond dropping the bytes:
991
+ * /
992
+ * / * it is a RESULT. The old surface returned `[]` for "no such file", "you may not read
993
+ * / this", and "this file genuinely has no history" alike — a gated empty indistinguishable
994
+ * / from a real one, which is the exact failure class this store exists to end. A refusal
995
+ * / now says so.
996
+ * / * the counts ride along. `everCount` vs `retainedCount` makes byte eviction impossible to
997
+ * / hide: a reader who sees them differ knows something was reclaimed, and `evictions`
998
+ * / carries the disclosure — chain sequence and evicted root — for each range.
999
+ * /
1000
+ * / Paging is by version number, which works as its own cursor because versions are dense and
1001
+ * / never renumbered: the next page starts at the last version returned plus one. Defaults
1002
+ * / return the whole history of any file a pre-FD engram could have held.
1003
+ */
1004
+ getMemoryHistory: ActorMethod<[string, [] | [bigint], [] | [bigint]], Result_56>;
1005
+ /**
1006
+ * / PUBLIC: the epoch alone, and deliberately nothing else (rotation study D4). A `rotatedAt[]`
1007
+ * / history would be a public, fleet-enumerable feed of when each owner terminated a trust
1008
+ * / relationship — readable by, among others, the party just terminated.
1009
+ */
1010
+ getMemoryKeyEpoch: ActorMethod<[], bigint>;
1011
+ /**
1012
+ * / BLS verification key for the shared memory-encryption key. Used by the
1013
+ * / client to verify the derived key. Static per (context, key_id) — cacheable.
1014
+ * /
1015
+ * / PUBLIC: intentionally unauthenticated — a vetKD public key reveals nothing secret and
1016
+ * / cannot decrypt anything — the sensitive derivation is getEncryptedMemoryKey
1017
+ * / below, which IS gated (read_memory) and returns key material encrypted to the
1018
+ * / caller's transport key. Do not add an auth guard here (breaks client caching).
1019
+ * / ⟨L7⟩ UPDATE, NOT QUERY, and this is the system call that forces it: the body awaits
1020
+ * / `VetKeys.ManagementCanister.vetKdPublicKey`. A query cannot await, so the round trip is the
1021
+ * / cost of getting a key nobody has to trust us for — which is the point of publishing it.
1022
+ * /
1023
+ * / ⟨Marker added 2026-08-23; the census row already said "L7 (vetKD pubkey call)" and the site did
1024
+ * / not carry it. Declared `public func` rather than `public shared`, which is why the naming rule
1025
+ * / in check-update-for-read.mjs did not see it — the census population did.⟩
1026
+ */
1027
+ getMemoryKeyVerificationKey: ActorMethod<[], Uint8Array | number[]>;
1028
+ /**
1029
+ * / Memory maintenance liveness. PUBLIC: ungated on purpose, like the anchor-push status — a stalled
1030
+ * / sweep or a failed storage check is exactly what a third party must be able to observe, and
1031
+ * / a gated read that failed to empty would report a healthy zero to anyone without a role.
1032
+ * / Counts and flags only — the paths involved are in the chained audit entries, where the
1033
+ * / access rules that govern them already apply.
1034
+ */
1035
+ getMemoryMaintainStatus: ActorMethod<[], MemoryMaintainStatus>;
1036
+ /**
1037
+ * / The DECLARED policy. Read it together with getMemoryRetentionGuards — on its own it is not
1038
+ * / what governs eviction.
1039
+ * / ⟨0.16.0⟩ ONE PROJECTION, absorbing what were two methods — and the fold is a correctness fix,
1040
+ * / not tidying.
1041
+ * /
1042
+ * / Declared policy and the guards holding it back were separate reads, and a console rendering
1043
+ * / only the first told an owner their policy was in force while a guard still held it. The old
1044
+ * / `.did` warned in prose that the two had to be read TOGETHER; a comment is not a mechanism, and
1045
+ * / the guard arms on the FIRST policy an owner ever sets — so the surface misled every owner who
1046
+ * / ever touched retention, from first use. Making it one record makes reading half of it
1047
+ * / impossible: the trap becomes structure.
1048
+ * /
1049
+ * / Refusal reasons of both merge: an empty policy reads as "nothing is capped, every version kept
1050
+ * / forever" — a claim about what this engram will DESTROY — and an empty guard list reads as
1051
+ * / "nothing is held back".
1052
+ */
1053
+ getMemoryRetentionPolicy: ActorMethod<[], Result_55>;
1054
+ /**
1055
+ * / The metrics reader this engram answers — `null` until the spawning registry names one.
1056
+ * /
1057
+ * / PUBLIC: an owner deciding whether to switch the read off needs to know who it is, and anyone
1058
+ * / comparing this engram's copy with the reader the registry publishes (`getMetricsReader` there)
1059
+ * / needs the same value. A canister id is not a secret.
1060
+ */
1061
+ getMetricsReaderId: ActorMethod<[], [] | [Principal]>;
1062
+ /**
1063
+ * / A guardian asking about their OWN standing.
1064
+ * /
1065
+ * / #NotFound and not #Refused, deliberately, even though this reads a roster no stranger may
1066
+ * / see: the only row it can ever return is the caller's own, so "you are not a guardian here" is
1067
+ * / a fact about the caller, told to the caller. There is nothing to leak by omission — which is
1068
+ * / the test the #NotFound arm sets.
1069
+ */
1070
+ getMyGuardianStatus: ActorMethod<[], Result_15>;
1071
+ /**
1072
+ * / ⟨0.16.0, NEW⟩ The gated half of the status() split.
1073
+ * /
1074
+ * / Every field is bare — no masking, no `authorized` discriminator — because reaching this record
1075
+ * / AT ALL is the authorization. An unauthorized caller gets `#Err(#Refused …)` and no record.
1076
+ * /
1077
+ * / `cyclesBalance` is a bare `Nat`, and that retires an argument this repo carried for weeks. It
1078
+ * / was `nat`, then widened to `opt nat` so a refusal could be `null`, which broke every published
1079
+ * / client (rule 4) and bought a masked answer nobody had asked for — the census could not even
1080
+ * / find a consumer that read the masked `0`. Behind a gate there is nobody to mask it from.
1081
+ */
1082
+ getOwnerConsole: ActorMethod<[], Result_54>;
1083
+ /**
1084
+ * / Owner + agents only (agents need it to avoid writing protected paths).
1085
+ * /
1086
+ * / A NAMED RECORD, not a Page: the setter replaces this list wholesale, so there is no window to
1087
+ * / page over and no `total` that could differ from `items.size()`. Forcing the Page shape here
1088
+ * / would be uniformity for its own sake — the census ratified the whole-value-config carve-out
1089
+ * / precisely so L3 does not become a rule applied past its meaning.
1090
+ * /
1091
+ * / The trap's `whyNotEmpty` clause is preserved as the `#Refused` reason: `[]` would read as "no
1092
+ * / path on this engram is protected", and an agent consults this list precisely to avoid
1093
+ * / writing one — so a fabricated empty here does not merely misinform, it invites the write the
1094
+ * / list exists to prevent.
1095
+ */
1096
+ getProtectedPaths: ActorMethod<[], Result_53>;
1097
+ /**
1098
+ * / Whether the metrics reader's read is answered — `true` from birth.
1099
+ * /
1100
+ * / PUBLIC: the promise that an owner can switch this read off can be checked only if the switch
1101
+ * / can be read — the reason the reader pointer is public too. It discloses one setting, never a row.
1102
+ */
1103
+ getSeatWeeksReadEnabled: ActorMethod<[], boolean>;
1104
+ /**
1105
+ * / Owner-only, Billing-class: the signing floor, the balance, one signature's price, and how many
1106
+ * / payment signatures the balance carries above the floor before `signX402Payment` is refused by
1107
+ * / name. The same numbers the check uses, so Billing can say only what the engram enforces.
1108
+ */
1109
+ getSigningFloor: ActorMethod<[], Result_52>;
1110
+ /**
1111
+ * / The registry that spawned this engram, if it recorded one.
1112
+ * /
1113
+ * / PUBLIC: it is the provenance claim. An engram asserting it is part of a fleet, under that
1114
+ * / fleet's attested template and rent rail, is asserting something a stranger must be able to
1115
+ * / check against the registry named here — and a provenance you need permission to read is not
1116
+ * / provenance. `null` says this engram makes no such claim, which is equally worth serving.
1117
+ */
1118
+ getSpawnedBy: ActorMethod<[], [] | [Principal]>;
1119
+ /**
1120
+ * / Read the engram-wide daily ceiling and what has been spent against it today, across every
1121
+ * / caller. ⟨2026-09-28, the owner's decision to add the ceiling⟩
1122
+ * / ⟨CORRECTED 2026-09-29, review finding X-8: "spent" means signed in x402 payments; typed-data
1123
+ * / and the engram's registration signatures are not counted here — see `setSpendCeiling`.⟩
1124
+ * /
1125
+ * / OWNER-ONLY, for the reason `getSpendPolicy` is: the limits are the owner's custody
1126
+ * / configuration, and the engram-wide total would also tell one agent how much the others spent.
1127
+ * / A refusal names this method (`Gated.gatedResult`) rather than answering null/0 — a ceiling of
1128
+ * / "none" and a spend of 0 are both real answers, so a fabricated one would be read as fact.
1129
+ */
1130
+ getSpendCeiling: ActorMethod<[], Result_51>;
1131
+ /**
1132
+ * / Read the caps in force for a caller.
1133
+ * /
1134
+ * / OWNER-ONLY, and this is where it diverges from the market's inbound twin, which is public.
1135
+ * / There the limits ride inside every 402 challenge, so withholding them would hide nothing.
1136
+ * / Here the engram serves no 402s at all: these caps are the owner's private custody
1137
+ * / configuration, and publishing them would tell any caller exactly how large a signing request
1138
+ * / can be before it needs an approval nobody is watching for.
1139
+ */
1140
+ getSpendPolicy: ActorMethod<[[] | [Principal]], Result_50>;
1141
+ getStorageStats: ActorMethod<[], Result_49>;
1142
+ /**
1143
+ * / Timer arm-state. PUBLIC and deliberately so: these timers are self-arming to save cycles,
1144
+ * / and an optimisation nobody can verify is an optimisation nobody should trust. Cheap to read,
1145
+ * / leaks nothing (booleans about our own scheduling).
1146
+ * /
1147
+ * / IDLE STEADY STATE (no webhook, no x402 sessions, no service jobs):
1148
+ * / alertTimerArmed=false sessionExpiryArmed=false jobExpiryArmed=false jobExpiryFastMode=false
1149
+ * /
1150
+ * / ⚠ CORRECTED 2026-08-19. This said `jobExpiryArmed=TRUE` and that it "stays true by design —
1151
+ * / ic402 keeps an hourly idle POLL because createJobFromReceipt is synchronous and cannot disarm a
1152
+ * / timer itself". Both halves are stale, and an ops reader comparing a live engram against this
1153
+ * / paragraph would have seen `false` and gone looking for a fault that is not there.
1154
+ * /
1155
+ * / The engram sets `setExpiryIdlePollSeconds(0)` in its actor body, and ic402's ServiceRegistry
1156
+ * / CANCELS the timer outright at 0 rather than re-arming it — so the hourly tick this paragraph
1157
+ * / promised has not existed since that line landed. Independently, B1 moved job creation to the
1158
+ * / market: the engram now serves no job method at all, so nothing can arm the timer in the first
1159
+ * / place. `jobExpiryArmed` reads false on an idle engram, and false is CORRECT.
1160
+ * /
1161
+ * / EXPECTED FALSE POSITIVE: for up to one interval after any install or upgrade,
1162
+ * / sessionExpiryArmed reads true with zero sessions. ic402's startTimers arms unconditionally
1163
+ * / because a persistent actor re-runs its init body BEFORE postupgrade restores stable sessions,
1164
+ * / so a predicate-gated arm would skip exactly the canisters that have live ones. The first tick
1165
+ * / disarms it. Still true minutes after an upgrade is a real bug — report it upstream.
1166
+ * / NOT the whole timer story. The hourly CYCLE timer — which also carries audit anchoring — is
1167
+ * / deliberately absent: it is a `transient let` armed unconditionally at init, so an "armed"
1168
+ * / boolean for it would read true forever and tell you nothing, exactly the false-positive the
1169
+ * / paragraph above describes for sessionExpiryArmed. Use getAnchorPushStatus() instead: last-tick
1170
+ * / TIMESTAMPS are evidence where an arm flag is only an intention.
1171
+ * /
1172
+ * / PUBLIC: the same standing as the two liveness reads above. Booleans and timestamps about this
1173
+ * / canister's own timers — nothing about content, callers or money — and a liveness signal only
1174
+ * / its owner can read cannot tell a third party that the engram is still running.
1175
+ */
1176
+ getTimerHealth: ActorMethod<[], TimerHealth>;
1177
+ /**
1178
+ * / PUBLIC: a cap identifies no user, and a caller deserves to know the rule before it stops them.
1179
+ * /
1180
+ * / ⟨0.16.0, L8⟩ Was owner-gated behind a trap. The disclosure law asks what the value reveals, and
1181
+ * / the answer here is nothing about anybody — it is a policy ceiling, not a balance or a history.
1182
+ * / Publishing it removes the trap AND the envelope: an ungated read has no refusal to carry, so
1183
+ * / wrapping it in `Result` would be ceremony that implies a gate exists.
1184
+ * /
1185
+ * / Predictability is itself the honesty posture: a limit that only reveals itself by refusing a
1186
+ * / top-up teaches the caller by failure. `/// PUBLIC:` is the marker the L8 gate greps for.
1187
+ */
1188
+ getTopUpLimits: ActorMethod<[], { cooldownSeconds: bigint; maxCkusdcE6s: bigint }>;
1189
+ /**
1190
+ * / ⟨0.16.0⟩ `walletBalance()` DELETED — a ONE-LETTER trap beside `walletBalances()`, and a strict
1191
+ * / projection of it: it returned `ExperimentalCycles.balance()`, which is `WalletBalances.cycles`.
1192
+ * /
1193
+ * / Two methods whose names differ by a single character, with the same gate and one a subset of
1194
+ * / the other, is a call site waiting to be written wrong — and wrong in the direction that
1195
+ * / silently reads cycles when it meant to read money. Doc callers (CLI-REFERENCE, Docs.vue) sweep
1196
+ * / to the survivor.
1197
+ * / RENAMED from `walletBalances` (L2.1: `get*` for a single value).
1198
+ * /
1199
+ * / Stays an UPDATE, marked per L7: it awaits three ICRC-1 ledgers. The name cannot say that, so
1200
+ * / the declaration does — a caller budgeting round-trips needs to know this is not a query.
1201
+ * /
1202
+ * / The ledger failure is `#Unavailable`, not `#Invalid`: a dependency refused or timed out, the
1203
+ * / request was fine, and retry is the correct response. That is the one arm in the whole set that
1204
+ * / means "try again", and it is the reason `Error` is a closed variant rather than a sentence.
1205
+ * /
1206
+ * / ⟨L7⟩ MARKER ADDED 2026-08-23, reasoning above UNCHANGED — this block already said "Stays an
1207
+ * / UPDATE, marked per L7: it awaits three ICRC-1 ledgers". It was marked in prose and invisible
1208
+ * / to any gate; the glyph is what `scripts/check-update-for-read.mjs` matches.
1209
+ */
1210
+ getWalletBalances: ActorMethod<[], Result_48>;
1211
+ /**
1212
+ * / Refusal reason preserved, and it is the clearest case of why a masked read is worse than no
1213
+ * / read: three empty strings with `configured = false` is a VALID-LOOKING answer meaning "this
1214
+ * / engram has no World ID configuration" — handed to a caller who merely lacks a grant. The
1215
+ * / fabrication is indistinguishable from the truth by construction.
1216
+ */
1217
+ getWorldIdConfig: ActorMethod<[], Result_47>;
1218
+ /**
1219
+ * / ⟨L7⟩ UPDATE, NOT QUERY: this awaits THREE system calls — `raw_rand()` for the nonce,
1220
+ * / `Call.signWithEcdsa` for the signature, and `worldIdRpPublicKey()` for the derived key. A
1221
+ * / query can do none of them.
1222
+ * /
1223
+ * / Owner-only: produce a World ID 4.0 relying-party context for the frontend's IDKit request.
1224
+ * / Valid iff the derived signer address (getWorldIdRpSignerAddress) is registered for this rp_id in
1225
+ * / the World Developer Portal. Short-lived (300s TTL, idkit-server's default) and single-purpose —
1226
+ * / it authorizes opening one verification request, nothing else.
1227
+ */
1228
+ getWorldIdRpContext: ActorMethod<[], Result_46>;
1229
+ /**
1230
+ * / Owner-only: the EVM address derived from the engram's dedicated World ID RP signing key (the
1231
+ * / "worldid-rp" tECDSA path). Register THIS address as the rp_id's signer in the World Developer
1232
+ * / Portal — the engram never holds or exports a private key (only threshold shares exist, on the
1233
+ * / subnet). Distinct from the payment/EVM address by construction.
1234
+ * /
1235
+ * / ⟨L7⟩ UPDATE, NOT QUERY, for TWO reasons and the second is the one a reader would miss. It
1236
+ * / awaits `worldIdRpPublicKey()` (management `ecdsa_public_key`), and it calls `denied()` on
1237
+ * / refusal — a state write, which a query cannot perform. So even if the key were cached this
1238
+ * / could not become a query without silently retiring its denial record (ADR-0002's class).
1239
+ */
1240
+ getWorldIdRpSignerAddress: ActorMethod<[], Result_43>;
1241
+ /**
1242
+ * / The verified IDKitResult, verbatim, as World's /api/v4/verify accepted it — the re-checkable
1243
+ * / artifact behind verifiedHuman. Role-gated because it carries the NULLIFIER.
1244
+ * / `Result<opt Text>` — and the double wrapper is the entire point, not redundancy.
1245
+ * /
1246
+ * / `#Ok(null)` means HONEST ABSENCE: no verification is on record, and you were entitled to ask.
1247
+ * / `#Err(#Refused …)` means you may not ask. Under the old bare `?Text` those two collapsed into
1248
+ * / one `null`, so a caller lacking a grant was told an unverified human stands behind this engram
1249
+ * / — a false claim about a person, produced by an authorization failure.
1250
+ * /
1251
+ * / The artifact stays role-gated because it carries the NULLIFIER. The public, anonymous answer to
1252
+ * / "is a human behind this engram" is `about().verifiedHuman`, which is a boolean and leaks
1253
+ * / nothing.
1254
+ * /
1255
+ * / ⟨CORRECTED 2026-08-21 — this said `metrics().verifiedHuman`, and `metrics()` no longer exists:
1256
+ * / L2.2 folded it and `status()` into `about()`, which carries the field. The sentence is a
1257
+ * / `///`, so the dead name was PUBLISHED in engram.did and pointed every client at a method the
1258
+ * / canister does not serve. The tombstones below and at `about()` are historical and correct as
1259
+ * / written; this one was present tense, which is the difference that matters.⟩
1260
+ */
1261
+ getWorldIdVerification: ActorMethod<[], Result_45>;
1262
+ /**
1263
+ * / ⟨0.16.0, L1⟩ THE EMERGENCY FAMILY. Every refusal below is `#Refused` or `#NotFound`, and the
1264
+ * / absence of a `#Conflict` here is the point: these are the calls someone makes while something
1265
+ * / is going wrong, and the only two answers that help are "you may not do this" and "there is
1266
+ * / nothing by that name". A missing PERMISSION is `#Refused` rather than `#Conflict` — the
1267
+ * / guardian's standing is what fell short, and no change to engram state would let them through.
1268
+ */
1269
+ guardianRevokeAgent: ActorMethod<[Principal], Result_1>;
1270
+ /**
1271
+ * / The HTTP surface: canister-info JSON, OAuth discovery documents, and the MCP route's query
1272
+ * / half. See the `http_request_update` twin below for what upgrades and why.
1273
+ * /
1274
+ * / PUBLIC: not a choice. The boundary node invokes this for every inbound HTTP request with no
1275
+ * / caller identity to gate on, so a gate here would refuse the only caller there is. Authorization
1276
+ * / lives INSIDE, per route — `/mcp` demands a bearer token, the discovery documents are meant to
1277
+ * / be world-readable by their own specs, and the canister-info JSON serves only facts already
1278
+ * / published by the queries above it.
1279
+ */
1280
+ http_request: ActorMethod<[HttpRequest], HttpResponse>;
1281
+ /**
1282
+ * / The update twin of the router above — the routes the query half UPGRADES so their responses
1283
+ * / are consensus-certified and served on the certified hostname.
1284
+ * /
1285
+ * / PUBLIC: for the same reason as its twin, and it must match. A route the query half upgrades
1286
+ * / but this half does not handle falls through to the 404 at the end, turning a serving fault
1287
+ * / into what reads as a wrong URL — half a fix being worse than none, as the /oauth/authorize
1288
+ * / arm inside records.
1289
+ */
1290
+ http_request_update: ActorMethod<[HttpRequest], HttpResponse>;
1291
+ /**
1292
+ * / ⟨0.16.0⟩ `isPaidMemoryReadEnabled()` DELETED — folded to `about().paidMemoryReadEnabled`
1293
+ * / (L2.6: one idiom for a boolean feature — a setter plus the flag on its family's projection).
1294
+ * / Its callers are a buyer's pre-check and the market canister, both ANONYMOUS, so the public
1295
+ * / projection is exactly where it belongs.
1296
+ * / PUBLIC: a wallet calls this BEFORE its user has any standing on this engram — that is what the
1297
+ * / call is for — so gating it would make the message unreadable at exactly the moment it is
1298
+ * / needed, and a signature given without it is a signature given blind.
1299
+ */
1300
+ icrc21_canister_call_consent_message: ActorMethod<
1301
+ [
1302
+ {
1303
+ arg: Uint8Array | number[];
1304
+ method: string;
1305
+ user_preferences: {};
1306
+ },
1307
+ ],
1308
+ | {
1309
+ Ok: {
1310
+ metadata: {
1311
+ utc_offset_minutes: [] | [number];
1312
+ language: string;
1313
+ };
1314
+ consent_message: { GenericDisplayMessage: string };
1315
+ };
1316
+ }
1317
+ | { Err: { description: string; error_code: bigint } }
1318
+ >;
1319
+ /**
1320
+ * / Owner-only: is the derived EVM address CACHED right now, without deriving it to find out.
1321
+ * /
1322
+ * / WHY A SEPARATE METHOD AND NOT A FIELD ON `getEvmAddress`. That method cannot answer this
1323
+ * / question by construction: when the cache is null it DERIVES, caches the result and returns it,
1324
+ * / so by the time a caller sees the reply the cache is populated either way. Asking it whether the
1325
+ * / cache had been populated changes the answer.
1326
+ * /
1327
+ * / WHY IT EXISTS AT ALL, since a public surface is never free on a canister meant to go public.
1328
+ * / `evmAddressCache` is money-classed and its annotation says why: derivation is deterministic, so
1329
+ * / a lost cache LOOKS harmless, but until something re-derives, the EVM payment quote advertises
1330
+ * / the fallback — an address that cannot receive. A window in which a live money surface publishes
1331
+ * / an unreceivable address is a money defect, not a cache miss. Nothing else in this canister
1332
+ * / reads that var — one reader and two writers, all in this file — so before this method there was
1333
+ * / no observation anywhere that could tell a survived cache from a rebuilt one, and the upgrade
1334
+ * / coverage gate carried a money-classed var nothing could prove.
1335
+ * /
1336
+ * / ⚠ IT MUST NEVER DERIVE. A version that fell back to deriving would answer `true` always and
1337
+ * / prove nothing — the same trap `getEvmAddress` sets for anyone trying to use it as a witness.
1338
+ * / It reads the var and nothing else, and it is a `query` precisely so that it CANNOT make the
1339
+ * / inter-canister call a derivation requires: the restriction is enforced by the system, not by
1340
+ * / this comment.
1341
+ * /
1342
+ * / Owner-gated because it reports on custody posture, and answered as a Result so that a
1343
+ * / wrong-identity caller gets a refusal rather than a bare `false` that reads as "no address yet".
1344
+ */
1345
+ isEvmAddressCached: ActorMethod<[], Result_44>;
1346
+ /**
1347
+ * / Issue an OAuth authorization code. Called by an OAuth client's sign-in bridge
1348
+ * / (an `/auth/connector`-style route) after II authentication. The client then
1349
+ * / redirects the user's browser to `redirectUri` with `?code=<this>` so the
1350
+ * / MCP client (e.g. claude.ai) can exchange it for a bearer token at /oauth/token.
1351
+ * /
1352
+ * / Owner-only: only the engram owner can authorize a Connector install.
1353
+ */
1354
+ issueAuthCode: ActorMethod<[string, string, string, [] | [string]], Result_43>;
1355
+ /**
1356
+ * / ⟨0.16.0⟩ `getCycleSnapshotSource` DELETED — folded into `CycleSnapshot.source`, one label per
1357
+ * / ROW. A single label for a whole ring misattributes every row recorded under the other source,
1358
+ * / and the source flips by design (self-call first, balance on fallback). Its documentation of
1359
+ * / what the two values mean lives on the type.
1360
+ * / Hourly (timestamp, totalMemoryReads, totalMemoryWrites) snapshots, ~30 days.
1361
+ * / Same guard + fail-to-empty shape as getCycleHistory. Diff consecutive rows for a
1362
+ * / per-engram activity time-series (retention instrumentation).
1363
+ * / RENAMED from `getActivityHistory` (L2.1); named fields replace a bare 3-tuple whose two Nats
1364
+ * / were positionally indistinguishable.
1365
+ * /
1366
+ * / Refusal reason preserved, and it is the sharpest of this family: a masked `[]` reads as a
1367
+ * / DORMANT engram and corrupts retention math — a fabricated empty here does not just misinform a
1368
+ * / reader, it feeds a wrong number into a decision about destroying data.
1369
+ */
1370
+ listActivitySnapshots: ActorMethod<[bigint, bigint], Result_42>;
1371
+ /**
1372
+ * / ⟨0.16.0⟩ THE PAGE EXEMPLAR. Trap → `#Refused`, bare array → `Result<Page<T>>` (L1 + L3).
1373
+ * /
1374
+ * / The refusal prose that used to be `gatedTrap`'s `whyNotEmpty` argument is not lost — it is why
1375
+ * / this method could never fail soft, and it now travels ON THE WIRE inside `#Refused` where a
1376
+ * / caller can actually read it, instead of inside a trap message only a log sees.
1377
+ * /
1378
+ * / `total` is the ROSTER SIZE, not `items.size()`. That distinction is the whole reason this
1379
+ * / shape exists here: `MAX_AGENTS` clamps the returned rows, and the old code returned the
1380
+ * / clamped array with nothing saying it had clamped — a caller reading 100 agents could not
1381
+ * / tell whether that was all of them. Now a clamped answer is self-describing, and the previous
1382
+ * / behaviour (silently truncate, look complete) is unrepresentable.
1383
+ * /
1384
+ * / `withheld` is 0: this roster is owner-only in whole, so there is no partial-visibility case.
1385
+ * / A method that filters rows by caller sets it — see L1's row-level honesty rule.
1386
+ */
1387
+ listAgents: ActorMethod<[bigint, bigint], Result_41>;
1388
+ /**
1389
+ * / The GUARDIAN-audience projection of the agent roster — three fields, not the full record.
1390
+ * /
1391
+ * / Two audiences, two methods (L1/L8), rather than one method masking fields by caller: a
1392
+ * / guardian needs enough to revoke (who, what they are called, whether they are active) and no
1393
+ * / more. Field-masking would make the same call return different shapes to different callers,
1394
+ * / which is the design L1 abolished — and it would put the decision about what a guardian may see
1395
+ * / inside a build closure where no gate can read it.
1396
+ * /
1397
+ * / Refusal reason preserved: `[]` reads as "this engram has no agents", and this is the list a
1398
+ * / guardian consults BEFORE REVOKING ONE. A fabricated empty here does not merely misinform —
1399
+ * / it tells someone acting under emergency powers that there is nothing to act on.
1400
+ */
1401
+ listAgentsForGuardian: ActorMethod<[bigint, bigint], Result_40>;
1402
+ /**
1403
+ * / Owner-only: rows carry caller, amount, operation and free-text rationale. The SDK omits it.
1404
+ * /
1405
+ * / The optional leading filter SURVIVES the L3 reshape — ratified (census tier-2 #8) rather than
1406
+ * / assumed, because Billing.vue calls the filtered form live and pushing the filter client-side
1407
+ * / would make the console fetch a queue to discard most of it.
1408
+ * /
1409
+ * / `total` counts the FILTERED set, not the whole queue: with a filter applied, "how many match"
1410
+ * / is the number a pager needs, and reporting the unfiltered count would make every filtered view
1411
+ * / claim more pages than it has.
1412
+ * /
1413
+ * / Refusal reason preserved: `[]` reads as "nothing is awaiting the owner's decision".
1414
+ */
1415
+ listApprovalRequests: ActorMethod<[[] | [ApprovalStatus], bigint, bigint], Result_28>;
1416
+ /**
1417
+ * / ⟨0.16.0⟩ `total` IS THE HEAD COUNTER, and on this method that is the entire point.
1418
+ * /
1419
+ * / The audit log is a bounded RING: it trims its tail, so "rows you can read" and "entries that
1420
+ * / have ever existed" are different numbers. The old bare array published only the first, which
1421
+ * / made a trimmed log indistinguishable from a complete one — and this is the evidence surface,
1422
+ * / where that difference IS the product. `totalAppended()` is monotonic across trims and is the
1423
+ * / same number `getCertifiedAuditHead` publishes, so a caller comparing page against head gets
1424
+ * / agreement by construction rather than by luck.
1425
+ * /
1426
+ * / Refusal reason preserved: for an unauthenticated integrity check the caller wants
1427
+ * / `getCertifiedAuditHead()`, which is public and subnet-certified. The BODIES are role-gated.
1428
+ * /
1429
+ * / ⟨2026-09-29, owner ruling follow-up 16 (B)⟩ AN AGENT READS ONLY THE ENTRIES IT CAUSED; the
1430
+ * / owner and guardians read everything (`RecordView`). So `limit` is a SPAN — how many record ids
1431
+ * / to examine from `start` — and an agent's page holds the entries in that span whose caller is
1432
+ * / its own key, with `withheld` counting the rest: `items.size() + withheld` is the span examined.
1433
+ * / For the owner and a guardian `withheld` is 0 and the page is the span. WHAT WOULD MAKE THIS
1434
+ * / WRONG: a reader who must see the whole record without being the owner or a guardian — the
1435
+ * / public certified head is the answer for integrity, and nothing else is.
1436
+ */
1437
+ listAuditEntries: ActorMethod<[bigint, bigint], Result_23>;
1438
+ /**
1439
+ * / ⟨0.16.0, L1 + L3 — census-ruled⟩ THE TWO-MECHANISM EXCEPTION DISSOLVES.
1440
+ * /
1441
+ * / This method used to answer THREE ways to one question: a list, an `#Err` text, and a trap,
1442
+ * / picked by which kind of caller asked. That split existed only because the return type could
1443
+ * / not carry a refusal — with `Result<Page<T>>` it can, so every caller gets one shape and the
1444
+ * / arm says which no it is. A paired agent lacking `canReadBackup` is `#Refused`; so is
1445
+ * / everyone else who may not ask. The trap is gone: `Debug.trap` is for invariant violations,
1446
+ * / never authorization (L1), and a refusal a caller cannot catch is not a better refusal.
1447
+ * /
1448
+ * / ⚠ THE RATIFIED LOCKSTEP EXCEPTION THIS CARRIED IS SUPERSEDED, not quietly dropped.
1449
+ * / `ADR-0002-listBackups-refusal-lockstep/listBackups` existed because published
1450
+ * / @engramx/client 0.15.0 declares `IDL.Vec(BackupMetadata)` here and cannot decode a variant at
1451
+ * / all — it throws — and @engramx/openclaw's dedup probe catches that throw and degrades to
1452
+ * / "skipped", so every database silently stops being backed up while the CLI reports success.
1453
+ * / That analysis was correct and is still correct. What changed is its PREMISE: plan v2 measured
1454
+ * / the installed base at zero external users (prod = two engrams, both ours; npm published
1455
+ * / 2026-08-14), so the population the ceremony protected does not exist. The SDK is republished
1456
+ * / at 0.16.0 in this same campaign. If an outside caller ever appears before that ships,
1457
+ * / this reasoning is void and the lockstep is owed again.
1458
+ * /
1459
+ * / `dbTypeFilter` DIES on the wire (census). The capability does not: `EngramClient.listBackups`
1460
+ * / keeps its optional filter and applies it to the page, so no caller loses the ability to ask
1461
+ * / "backups of this database" — it stops being a thing the canister has to page around.
1462
+ */
1463
+ listBackups: ActorMethod<[bigint, bigint], Result_39>;
1464
+ /**
1465
+ * / List all bearer tokens — Active, Revoked, and Expired. Owner uses this in
1466
+ * / the dashboard to show installed Connectors (claude.ai, Claude Desktop, etc.).
1467
+ * / Refusal reason preserved from the trap: `[]` reads as "no connector is installed on this
1468
+ * / engram" — a claim about what can REACH it. An owner auditing access cannot tell that from
1469
+ * / "you may not see the list", and the two are opposite facts.
1470
+ * /
1471
+ * / `bearerTokenStore.list()` already resolves each token's status at read time (a token that
1472
+ * / merely stopped being used is reported `#Expired`, not a stale `#Active`), so the page carries
1473
+ * / the same honesty the store gained on 2026-08-17.
1474
+ */
1475
+ listBearerTokens: ActorMethod<[bigint, bigint], Result_38>;
1476
+ /**
1477
+ * / The condense checkpoints in the retained log at or above `startSeq`, oldest first.
1478
+ * /
1479
+ * / ⟨0.16.0, NEW⟩ The other half of the split above. A checkpoint is the only surviving record of a
1480
+ * / stretch of chain that no longer exists, so this is the list that accounts for the distance
1481
+ * / between `firstAvailableSeq` and the entries an owner remembers writing — without it, a
1482
+ * / condensed prefix is a gap the owner has to take on trust.
1483
+ * /
1484
+ * / Owner-only like every other archive surface, and for the same structural reason: these rows
1485
+ * / carry the chain positions and roots of entries whose paths were inside the hash preimage.
1486
+ */
1487
+ listCondenseCheckpoints: ActorMethod<[bigint, bigint], Result_37>;
1488
+ /**
1489
+ * / ⟨0.16.0⟩ `metrics()` DELETED — absorbed by `about()`.
1490
+ * /
1491
+ * / Two public projections of one canister (L2.2): `metrics()` and `status()` both answered "what
1492
+ * / is this engram like" and disagreed on which counters they carried, so a consumer had to fetch
1493
+ * / both and know which one owned each field. Every field here survives on `about()`, day-flooring
1494
+ * / included.
1495
+ */
1496
+ listCycleSnapshots: ActorMethod<[bigint, bigint], Result_36>;
1497
+ /**
1498
+ * / Same `withheld` treatment as listMemoryFiles — the tombstone listing filtered reserved paths
1499
+ * / for non-owners just as silently, and a caller could not tell a filtered tombstone list from a
1500
+ * / complete one. Counted before slicing, so policy-hidden rows never blur into paging.
1501
+ */
1502
+ listDeletedMemoryFiles: ActorMethod<[bigint, bigint], Result_35>;
1503
+ /**
1504
+ * / The registered shapes — E3: encodeTypeString is the display artifact, verbatim.
1505
+ * / Stays on the engram under B1 (hybrid): EIP-712 signing is custody, and custody does not leave.
1506
+ * /
1507
+ * / Refusal reason preserved: `[]` reads as "this engram can sign nothing" — a claim about SIGNING
1508
+ * / AUTHORITY, which is not a thing to hand an unauthorized reader. The public trail of every
1509
+ * / registration remains the audit chain under getCertifiedAuditHead.
1510
+ */
1511
+ listEip712Types: ActorMethod<[bigint, bigint], Result_34>;
1512
+ /**
1513
+ * / Stays on the engram under B1 (hybrid): withdrawal custody does not leave.
1514
+ * /
1515
+ * / NAMED item, not a `(Text, Int)` tuple. The Int is an activation time, and a bare Int beside a
1516
+ * / bare Text told a reader nothing about which was which — the same defect fixed on the purge log.
1517
+ * /
1518
+ * / Refusal reason preserved, and it has two halves that matter separately: `[]` reads as "this
1519
+ * / engram may withdraw nowhere", OR — worse — as "no allowlist is in force", which is the
1520
+ * / opposite security posture. It also erases any pending 24h activation from view.
1521
+ */
1522
+ listEvmWithdrawDestinations: ActorMethod<[bigint, bigint], Result_33>;
1523
+ /**
1524
+ * / Accessible by owner and guardians.
1525
+ * /
1526
+ * / Refusal reason carried over from the trap, because it is the sharpest example of why this
1527
+ * / surface may not fail soft: `[]` reads as "this engram has nobody who can freeze payments or
1528
+ * / pause writes" — a claim about who can STOP it. A caller who cannot tell that from "you may not
1529
+ * / see the roster" has been told the engram is unguarded when it may be fully guarded.
1530
+ */
1531
+ listGuardians: ActorMethod<[bigint, bigint], Result_32>;
1532
+ /**
1533
+ * / The export receipts in the retained log at or above `startSeq`, oldest first.
1534
+ * /
1535
+ * / ⟨0.16.0, L3⟩ ONE LIST, ONE QUESTION. This method used to return receipts AND checkpoints
1536
+ * / together behind a backward `before`/`max` cursor. They answer different questions — what may be
1537
+ * / condensed, and what already was — so a caller wanting one paid to decode the other, and the
1538
+ * / merged shape had to carry two arrays, a truncation flag and an opaque cursor to stay honest
1539
+ * / about a walk that served both. `listCondenseCheckpoints` is the other half.
1540
+ * /
1541
+ * / The cursor dies with it (census R6): paging is by ABSOLUTE SEQ now, forward, so a caller resumes
1542
+ * / at `scannedThroughSeq + 1` and is finished when that passes `page.total`. `scanTruncated` is
1543
+ * / gone because it has nothing left to say — "I stopped at entry N" is the same claim it made, and
1544
+ * / says it as a position rather than a flag a reader has to pair with a second field.
1545
+ * /
1546
+ * / Read `MemoryRouter.ReceiptPage` before reading `page.total` as a receipt count. It is not one;
1547
+ * / it is the chain's length, and the declaration says why.
1548
+ */
1549
+ listMemoryExportReceipts: ActorMethod<[bigint, bigint], Result_31>;
1550
+ /**
1551
+ * / ⟨0.16.0⟩ THE `withheld` EXEMPLAR — L1 names this exact method as the defect it fixes.
1552
+ * /
1553
+ * / A non-owner's answer silently dropped every `config/` and `secrets/` row. Not "refused the
1554
+ * / call" and not "returned a marker" — the rows simply were not there, with nothing in band
1555
+ * / saying so, and the filtering happened INSIDE a combinator closure where neither honesty gate
1556
+ * / could see it. Meanwhile `readMemory` returned an explicit refusal for the very same paths.
1557
+ * / Same policy, same caller, two answers, and the quiet one was the lie.
1558
+ * /
1559
+ * / `withheld` is now the count of rows policy removed. It leaks no names — which is the point:
1560
+ * / the caller learns THAT something is hidden without learning WHAT, so an agent can tell a
1561
+ * / short listing from a complete one and stop inferring the engram is emptier than it is.
1562
+ * /
1563
+ * / Note the count is computed from the unfiltered list before slicing, so it reports rows hidden
1564
+ * / by POLICY, never rows merely off the end of this page — those are `total`'s job. Conflating
1565
+ * / the two would rebuild the ambiguity in a new place.
1566
+ */
1567
+ listMemoryFiles: ActorMethod<[bigint, bigint], Result_30>;
1568
+ /**
1569
+ * / One page of the memory log, seq-ordered, optionally narrowed to one author.
1570
+ * /
1571
+ * / THE WINDOW IS THE CURSOR, and the page now states it. The window is
1572
+ * / `items.size() + withheld` entries starting at `max(startSeq, firstAvailableSeq)`; advance by
1573
+ * / that, never by "last entry returned + 1", which stalls forever on the first empty page. Stop
1574
+ * / when the window passes `total`.
1575
+ * /
1576
+ * / ⟨0.16.0, L3 — CENSUS CONFLICT, RECORDED⟩ The census row says `→R<P<MemoryLogEvent>>` and
1577
+ * / "authorFilter dropped (kills the filtered-window cursor stall)". The stall is real and the
1578
+ * / diagnosis is right; amputating the filter is not the only cure, and it is the expensive one —
1579
+ * / `Archive.vue` ships a working author-filter UI, and "what did this agent write" is a
1580
+ * / question an owner asks of an evidence log. The filter STAYS. What kills the stall instead is
1581
+ * / `withheld`: it carries the count this filter removed from the window, so a short or empty
1582
+ * / filtered page is no longer ambiguous between "nobody wrote here" and "the window was small",
1583
+ * / and the correct cursor advance is computable from the page itself. `pageCap` therefore dies
1584
+ * / with nothing lost — it existed only to disclose a window that `items.size() + withheld` now
1585
+ * / states directly.
1586
+ * /
1587
+ * / `firstAvailableSeq` and `head` sit BESIDE the page rather than in it. They are facts about the
1588
+ * / chain, not this slice: the condense floor tells a caller reading an archived range where the
1589
+ * / log now begins instead of letting them read it as empty, and the head is what a third party
1590
+ * / checks the page against. Flattening to a bare `Page` to satisfy the shape would buy uniformity
1591
+ * / with the disclosures that make the page verifiable — the hidden-bound defect the census itself
1592
+ * / names on previewCondense's row.
1593
+ */
1594
+ listMemoryLog: ActorMethod<[bigint, bigint, [] | [Principal]], Result_29>;
1595
+ /**
1596
+ * / The caller's OWN spend-approval requests. ⟨0.16.0, L1 + L3 — fixed 2026-08-18⟩
1597
+ * /
1598
+ * / Two defects in seven lines, and the first is the one this release exists to remove:
1599
+ * /
1600
+ * / · `if (Principal.isAnonymous(msg.caller)) return []` is a FABRICATED EMPTY. An anonymous
1601
+ * / caller was told "you have no approval requests", which is a claim about their queue rather
1602
+ * / than about their identity, and is indistinguishable from the honest answer. It refuses now.
1603
+ * / · The reply was uncapped over `pendingApprovals`, which NEVER SHRINKS — the hourly expiry
1604
+ * / timer flips a row's status to `#Expired` and deletes nothing. So the array grew for the
1605
+ * / life of the engram, and a caller with enough history would eventually get a reply too
1606
+ * / large to decode: not a truncated list, no list at all.
1607
+ * /
1608
+ * / The caller-scoping is not `withheld`: rows belonging to someone else were never this caller's
1609
+ * / to see, so `total` over their own rows is the honest count and nothing is hidden FROM them.
1610
+ * / (The unbounded MAP is filed separately — pruning an approval record destroys evidence of what
1611
+ * / was asked, which is a retention ruling rather than a shape fix.)
1612
+ */
1613
+ listMyApprovalRequests: ActorMethod<[bigint, bigint], Result_28>;
1614
+ /**
1615
+ * / The payer's own sessions, live ones first. PAYER-SCOPED: a caller sees only their own, which
1616
+ * / is why this needs no role — a session id is not a secret from the person who paid for it.
1617
+ * /
1618
+ * / ⟨2026-10-02, paged⟩ Takes `(start, limit)` like every other list here, capped at
1619
+ * / `MAX_SESSIONS_PAGE` rows per call; `total` is how many of the caller's sessions still exist.
1620
+ * / It took no arguments, and a cursor added after the freeze is an argument-list change every
1621
+ * / client would break on — the market paged its own pending withdrawals before its cut for the
1622
+ * / same reason. The order is the order sessions were opened.
1623
+ */
1624
+ listMySessions: ActorMethod<[bigint, bigint], Result_27>;
1625
+ /**
1626
+ * /
1627
+ * / ⟨0.16.0, L3⟩ Paged and enveloped like every other `list*`, and the envelope here is uniformity
1628
+ * / rather than gating: this method cannot refuse anybody, so `#Err` is unreachable on it. That is
1629
+ * / deliberate — the off-chain verifier that reads this chain reads several other lists beside it,
1630
+ * / and one shape for all of them is worth more than saving a variant tag on the one that is
1631
+ * / public. `total` is the FULL chain length, so a verifier holding a short page can tell it has
1632
+ * / not seen the whole custody history — the distinction a bare array could not express.
1633
+ * /
1634
+ * / PUBLIC: custody history is the answer to "is this engram what it claims to be", and it is
1635
+ * / asked by strangers. `verifyEngramActiveOwner` on the registry answers only about the owner
1636
+ * / IT recorded, so this chain is what a caller composes with when currency matters — which it
1637
+ * / cannot do if it needs a role here.
1638
+ */
1639
+ listOwnershipTransfers: ActorMethod<[bigint, bigint], Result_26>;
1640
+ /**
1641
+ * / ⟨2026-09-29, the platform's question from the build review⟩ OWNER-ONLY: how many payment
1642
+ * / signatures each agent has obtained today, and the daily limit (200, `PaymentSignCap`). The
1643
+ * / owner's console stated the rule and showed no number, because nothing served one; a number it
1644
+ * / made up would be a fabricated zero. Anyone else is refused by name (`#Refused
1645
+ * / listPaymentSignatureCounts: …`), never answered with zeros. Paged like `listAgents`, in the same
1646
+ * / order, one row per agent in the roster; each count is the agent's, taken by its root as the
1647
+ * / signer takes it, so every key the agent holds here shows the same number. The owner is not
1648
+ * / counted and has no row; the marketplace's count is not an agent's and is not here. WHAT WOULD
1649
+ * / MAKE THIS WRONG: a count kept by something other than the agent's root (`PaymentSignCap.rowFor`
1650
+ * / says so beside it).
1651
+ * /
1652
+ * / ⟨2026-09-30, following the owner's answer 4 of that date⟩ "is not here" no longer holds: the
1653
+ * / marketplace's one shared count today is in the reply's `marketplace` field, with the limit this
1654
+ * / engram enforces for it — beside the agents, never a row among them
1655
+ * / (`PaymentSignCap.marketplaceRow`). Null when no marketplace is set.
1656
+ */
1657
+ listPaymentSignatureCounts: ActorMethod<[bigint, bigint], Result_25>;
1658
+ /**
1659
+ * / Agent records removed by a reset. Each row is a NAMED record with the fields `principal`,
1660
+ * / `name`, `registeredAt` and `purgedAt` — read them BY NAME, never by position.
1661
+ * / ⟨2026-09-29, the vocabulary ruling: pairing is the one verb that admits an agent⟩ The field
1662
+ * / this prose calls `registeredAt` is now `pairedAt`, on the served row and on the agent record
1663
+ * / it is copied from. What is said below about the two timestamps holds for `pairedAt`.
1664
+ * /
1665
+ * / The names are the whole point, not decoration. Both timestamps are a bare Int, so they were
1666
+ * / positionally indistinguishable at the client: a decoder that swapped registeredAt and
1667
+ * / purgedAt would type-check everywhere and show up only as nonsense in a UI. This prose used to
1668
+ * / describe the row as a positional 4-tuple and readers duly destructured it as one — the same
1669
+ * / bug, twice, in two different repos (corrected 2026-08-16). `agentPurgeLog` really is a
1670
+ * / 4-tuple in stable state; the SERVED shape is not, and that seam is where the mistake starts.
1671
+ * /
1672
+ * / resetEngram HARD-DELETES agent records so a purged principal can be invited back
1673
+ * / (owner ruling 2026-08-15). That makes the reset a genuine clear rather than a permanent burn —
1674
+ * / but it also means the `agents` map is no longer evidence that a principal ever held access,
1675
+ * / and the audit chain cannot stand in: it is a bounded ring that trims its oldest entries, so
1676
+ * / agent.pair rows are evicted over the life the rent model assumes. This is that
1677
+ * / evidence, and it is why the tombstone is written rather than the roster simply dropped.
1678
+ * /
1679
+ * / Owner-gated and TRAPS on refusal: an empty list must mean "no reset has removed an agent",
1680
+ * / never "you may not ask".
1681
+ * / ⟨CORRECTED 2026-10-02: it no longer traps. It is gated through `gatedResult`, so a refusal
1682
+ * / comes back as an `Err` VALUE that names this method — still never as an empty page, which is
1683
+ * / the property the sentence above was protecting.⟩
1684
+ * / RENAMED from `getOperatorPurgeLog` (L2.1: `get*` returns one value, `list*` returns a Page —
1685
+ * / the old name promised a scalar and delivered an array).
1686
+ * /
1687
+ * / Refusal reason preserved: an empty list must mean "no reset has removed an agent", never
1688
+ * / "you may not ask". On an evidence trail those are not close.
1689
+ * /
1690
+ * / Named record, not a 4-tuple. Both Ints are timestamps and were positionally indistinguishable
1691
+ * / at the client — swapping registeredAt and purgedAt would have type-checked everywhere and been
1692
+ * / visible only as nonsense in a UI.
1693
+ * /
1694
+ * / ⟨2026-09-29, review finding LIFE-2⟩ Each row now also carries the agent's `root`, the
1695
+ * / `invite` its enrolment named, and `ended` — why and on what day its engagement ended (its own
1696
+ * / earlier ending, or the reset) — the facts `resyncAgentEdges` re-sends. The stored rows are
1697
+ * / served as they are.
1698
+ */
1699
+ listPurgedAgents: ActorMethod<[bigint, bigint], Result_24>;
1700
+ /**
1701
+ * / ⟨0.16.0⟩ ONE ACCESSOR, folding `readReadLog` and `getDenialLog` — and the fold only became
1702
+ * / safe because of a change made earlier in this same leg.
1703
+ * /
1704
+ * / They were two methods over the SAME log behind the SAME gate. `getDenialLog`'s own declaration
1705
+ * / explained why the split existed: nothing published this log's head, so a client could only
1706
+ * / reach the OLDEST retained entries, and a "recent refusals" band built on `readReadLog` would
1707
+ * / have rendered the oldest slice of a 10,000-entry ring under those words. That rationale died
1708
+ * / when the Page conversion started publishing `total = totalAppended()` — the head is now a fact
1709
+ * / a caller can read, so paging backward from it is ordinary arithmetic.
1710
+ * /
1711
+ * / The census proposed deleting `readReadLog` outright as a "duplicate accessor". Checked at the
1712
+ * / site, that premise was false: `getDenialLog` filtered `not e.success`, so deleting the other
1713
+ * / would have removed the only way to read SUCCESSFUL entries — and this ring is overwhelmingly
1714
+ * / successful MCP reads. Folded instead, which keeps both capabilities and still ends the pair.
1715
+ * /
1716
+ * / ⚠ `limit` IS A SPAN, NOT A ROW COUNT, and the same in both modes: it is how many log ids to
1717
+ * / EXAMINE starting at `start`. Unfiltered, items == the entries in that span. Filtered, items is
1718
+ * / however many of them matched — fewer, and that is not truncation. This is the one honest
1719
+ * / reading, because the alternative (keep scanning until `limit` rows match) hides how far it
1720
+ * / looked, which is precisely what `getDenialLog` had to disclose with `scannedFrom`/`more`.
1721
+ * / A caller knows exactly which ids were examined: `[start, start + limit)`.
1722
+ * /
1723
+ * / `earliest` is gone as a field and lost nothing: entries carry their own `id`, so a caller
1724
+ * / paging from 0 reads the oldest retained id off the first item. That is L3's stated design —
1725
+ * / items self-identify — rather than a second number to keep in sync.
1726
+ * /
1727
+ * / `withheld` is 0 even when filtering. The filter is CALLER-REQUESTED; `withheld` means rows
1728
+ * / POLICY removed. Overloading it would rebuild the ambiguity this campaign exists to remove.
1729
+ * /
1730
+ * / ⚠ **CORRECTED 2026-08-21, BESIDE the paragraph above because it is what the caller contract
1731
+ * / USED to be: THAT RULE WAS REVERSED ON 2026-08-18 AND THIS COMMENT DID NOT FOLLOW.** The body
1732
+ * / below computes `withheld = examined.size() - kept.size()`, and its own dated note explains
1733
+ * / why: `withheld = 0` beside a filter is the FABRICATED-COMPLETE PAGE, and this is the worst
1734
+ * / method in the file to have it on — `successFilter = ?false` is how the denial band asks "who
1735
+ * / was refused here", and a short page claiming nothing was withheld says the engram examined
1736
+ * / this window and found no refusals, when it examined `span` rows of which most were successes.
1737
+ * /
1738
+ * / So `withheld` now means BOTH policy-removed and filter-removed rows, and a caller can recover
1739
+ * / the examined span as `items.size() + withheld` — which is the successor to the retired
1740
+ * / `scannedFrom`/`head` window, and the number a UI needs to say what it actually looked at
1741
+ * / rather than implying it looked at everything.
1742
+ * /
1743
+ * / This mattered beyond the file: doc comments are emitted into `engram.did`, so every SDK and
1744
+ * / hand-written client has been reading the pre-fix rule off the interface for three days.
1745
+ * /
1746
+ * / Named `listReadLog`, not the census's `listDenialEntries`: that name assumed only the denial
1747
+ * / half survived. A method serving every row must not be named for one of them.
1748
+ * /
1749
+ * / Refusal reason preserved from both: this log has NO public counterpart — no certified head to
1750
+ * / fall back to — so an empty answer would falsely assert nobody has read this record, and an
1751
+ * / empty denial band would assert nobody has ever been refused here.
1752
+ * /
1753
+ * / WHAT "success = false" MEANS, PRECISELY, kept from getDenialLog because it is easy to misread:
1754
+ * / REFUSED-OR-FAILED, not authorization-denied alone. `denied()` writes authz refusals here, and
1755
+ * / so do settle failures, webhook auto-disables, expiry sweeps and MCP rate limits. Do not narrow
1756
+ * / this to a name it does not carry.
1757
+ * /
1758
+ * / ⟨2026-09-29, owner ruling follow-up 16 (B)⟩ An agent reads only the entries it caused, here as
1759
+ * / on the chained record — the same `RecordView` filter, and `withheld` counts what it removed
1760
+ * / together with what `successFilter` removed. WHAT WOULD MAKE THIS WRONG: see `listAuditEntries`.
1761
+ */
1762
+ listReadLog: ActorMethod<[[] | [boolean], bigint, bigint], Result_23>;
1763
+ /**
1764
+ * / Same visibility as listAuditEntries: the owner, this engram's agents, and ACTIVE guardians
1765
+ * / see disputes. An unauthorized read REFUSES — it does not return an empty list, because an
1766
+ * / empty list reads as "no disputes have been filed", which is a claim, not an absence of one.
1767
+ * / RENAMED from `getRepudiations` (L2.1). Refusal reason preserved: an empty list would read as
1768
+ * / "no disputes have been filed" — and a dispute record that can be mistaken for an absence of
1769
+ * / disputes is worse than no record at all. Not public by design.
1770
+ * /
1771
+ * / ⟨CORRECTED 2026-09-29, owner ruling follow-up 16 (B)⟩ "Same visibility as listAuditEntries"
1772
+ * / still holds, and so the first sentence no longer does: an agent reads only the record entries it
1773
+ * / caused, and every dispute here is the owner's own `memory.repudiate` entry. So the owner and
1774
+ * / guardians get the rows; an agent gets an empty page whose `withheld` counts the rows in its
1775
+ * / window — which says disputes exist without showing them, never "none have been filed". WHAT
1776
+ * / WOULD MAKE THIS WRONG: a ruling that an agent may see the disputes of its own writes; this would
1777
+ * / then have to look up each disputed version's writer, which it does not do today.
1778
+ */
1779
+ listRepudiations: ActorMethod<[bigint, bigint], Result_22>;
1780
+ /**
1781
+ * / Owner: advance the review cursor — "I have seen everything up to and including uptoAuditId"
1782
+ * / (null = everything at the current head). Bounded so the attestation can never cover entries
1783
+ * / the console did not render; clamped monotonic (the cursor never moves backward) and to the
1784
+ * / current head (never attests the future). Logged, so the review itself is part of the record.
1785
+ * /
1786
+ * / Deliberately filter-agnostic: the cursor is a plain audit id in the CHAINED log's one id space
1787
+ * / (every family qualifiesForReview admits is written to auditLogger, so they share that space),
1788
+ * / and this never inspects an operation or a role. Widening what the review shows therefore
1789
+ * / changes only which ids the console can pass here — it cannot desynchronise the cursor.
1790
+ */
1791
+ markAgentWritesReviewed: ActorMethod<[[] | [bigint]], Result_8>;
1792
+ /**
1793
+ * / The AGENT's current key nominates the key that will replace it. Nothing moves yet: the new
1794
+ * / key must accept, by its own call, within 24 hours (`acceptAgentKeyNomination`). One pending
1795
+ * / nomination per agent — a new one replaces the earlier one, and the record says which. Refused,
1796
+ * / with nothing changed, for a caller that is not an active agent here and for a key that could
1797
+ * / not hold the record (`KeyReplacement.nomineeRefusal`).
1798
+ */
1799
+ nominateAgentKey: ActorMethod<[Principal], Result_1>;
1800
+ /**
1801
+ * / An AGENT paired here asks this engram to open an engram of its own. This engram attaches 1.3 T of
1802
+ * / its own cycles to the registry's `sysSpawnChild`; the agent's lasting key owns what is opened, and
1803
+ * / the engram is recorded as opened through this one. Answers the new engram's canister id.
1804
+ * /
1805
+ * / APPROVING IS GIVING: the owner allowed this with `setChildAllowance`, and what is attached is the
1806
+ * / agent's from the moment that engram exists. Nothing is ever taken back, and the registry never
1807
+ * / funds that engram — its owner (the agent) tops it up.
1808
+ * /
1809
+ * / ORDER, with no await before the allowance is taken: the caller is an active agent; there is a
1810
+ * / registry; payments are not frozen (opening sends this engram's cycles out of it, and a freeze is
1811
+ * / the brake a guardian holds over resources leaving); the balance carries the attachment above this
1812
+ * / engram's own reserve; then one opening is TAKEN from the agent's allowance in this message, and only
1813
+ * / then is the registry called. If the registry refuses or cannot be reached, the opening is GIVEN
1814
+ * / BACK (one added to the current count) and the cycles the call did not use come back by the
1815
+ * / network's refund. Every outcome is written to the record under `agent.openChild` in the message
1816
+ * / that hears the registry's answer, before the reply — in the alerts' money class.
1817
+ * /
1818
+ * / ⟨CORRECTED 2026-10-01, review F1 and F4 — the sentence "If the registry refuses or cannot be
1819
+ * / reached, the opening is GIVEN BACK" above is what was first built.⟩ The opening is given back only
1820
+ * / when the WHOLE attachment came back as the call's refund (the registry accepted none of it) and
1821
+ * / the owner has not set this agent's count since the take (`ChildAllowance.settle`). A refusal after
1822
+ * / the registry accepted the cycles (the template would not install, or the key came to own an
1823
+ * / engram meanwhile) leaves the 1.3 T in a canister the agent's key controls; giving the opening back
1824
+ * / then let an allowance of 1 drain this engram 1.3 T per call. Now that opening is spent and the
1825
+ * / reply says so.
1826
+ * /
1827
+ * / WHAT WOULD MAKE THIS WRONG: an await added between `ChildAllowance.take` and the registry call; the
1828
+ * / registry's `CHILD_MIN_ATTACHED_CYCLES` moving without `CHILD_ATTACH_CYCLES`.
1829
+ */
1830
+ openChildEngram: ActorMethod<[], Result_21>;
1831
+ openSession: ActorMethod<[SessionConfig, PaymentSignature], Result_20>;
1832
+ /**
1833
+ * / Withdraw tokens to the owner's principal. This is the ONLY way to
1834
+ * / move tokens out of the engram to an external address, and the
1835
+ * / destination is always hardcoded to the owner.
1836
+ * / NOT freeze-gated: the owner always controls their own funds.
1837
+ * / Guardian freeze only blocks agent/public operations.
1838
+ */
1839
+ ownerWithdraw: ActorMethod<[TokenAmount, [] | [ActionAuth]], Result_8>;
1840
+ /**
1841
+ * / ⟨0.16.0⟩ `payRentFromEarnings` DELETED — ruled TWICE (B1 and B2), and it was the single
1842
+ * / clearest violation of the OSS/platform split in this repo.
1843
+ * /
1844
+ * / It hand-declared four cashier methods inline, read `getFeeSchedule`, computed
1845
+ * / `priceE6 = rentUsdE6PerEngramYear * months / 12`, and deposited `priceE6 + 3 * CKUSDC_FEE`
1846
+ * / under a comment explaining that three is "the three token fees the cashier's rail spends" —
1847
+ * / a PUBLIC canister hardcoding how many ledger fees a PRIVATE one consumes internally. Any
1848
+ * / change to the cashier's rail silently mispriced this call.
1849
+ * /
1850
+ * / It also carried the only RE-ENTRANT cross-canister chain in the system: engram →
1851
+ * / cashier.payRentWithStablecoin → (registry, ledger, CMC …) → back into the SAME engram's
1852
+ * / sysRecordFeeEvent while the originating message was still suspended, both writing the same audit
1853
+ * / ring, with no lock.
1854
+ * /
1855
+ * / Rent is the cashier's entirely (B2). Owners pay through the cashier's rails; the engram keeps
1856
+ * / append-only receipts and no fee math.
1857
+ * / ⟨0.16.0, L1 — census-ruled⟩ THE ONE-SHOT ARM. Re-redemption is `#Err(#Conflict)`, named in
1858
+ * / the census row for this method, and it is the arm the whole guard exists to express: this
1859
+ * / principal HAS held agent access, and no code will give it back. A caller reading
1860
+ * / `#Conflict` knows to pair a fresh key; a caller reading `#Refused` would keep presenting the
1861
+ * / same identity, which is exactly the loop the one-shot rule was written to stop.
1862
+ * / Redeem an invite code minted by `createAgentInvite`. The CALLER becomes the agent, so
1863
+ * / redeem from the wallet that will do the work.
1864
+ * /
1865
+ * / ⚠ IT REFUSES ANY CALLER THAT ALREADY HOLDS A RECORD — `#Active`, `#Revoked` or `#Resigned`.
1866
+ * / The `#Revoked` case is the one that matters: revocation is a soft status change, so allowing
1867
+ * / a revoked principal to redeem a fresh invite would be a self-un-revoke. To CHANGE an existing
1868
+ * / agent's permissions the owner uses `setAgentPermissions`; this method is only ever the
1869
+ * / first admission of a principal.
1870
+ * /
1871
+ * / A GUARDIAN cannot redeem one either. A guardian is an independent check on agents, so one
1872
+ * / wallet must not hold both roles — use a separate wallet.
1873
+ * /
1874
+ * / Anonymous callers are refused, and every refusal above is recorded in the denial log.
1875
+ * /
1876
+ * / ⟨RESHAPED 2026-09-28, owner decision: one lasting identity per agent — one root key per agent,
1877
+ * / with an enrolled key per client⟩ The argument is one record: the invite `code` and an
1878
+ * / `enrolment` statement signed by the agent's ROOT key naming this engram, the calling key and
1879
+ * / this code (`Enrolment.verify`). The root is stored on the record and is what the registry keeps
1880
+ * / the track record under. REQUIRED, not optional: every engram launches on this code (the
1881
+ * / building-phase rule, 2026-09-27), so there is no key without a root and no second path for one.
1882
+ * / Two more refusals, each leaving the invite unconsumed: a statement that does not verify, and a
1883
+ * / root that already holds an ACTIVE key here (`Enrolment.activeKeyOf` — one active key per agent
1884
+ * / per engram). The one-shot rule and the five-active cap are unchanged and still read the KEY.
1885
+ * / ⟨CORRECTED 2026-09-29, the cycle-drain hole measured that day⟩ "each leaving the invite
1886
+ * / unconsumed" holds only until the invite's fifth failed statement check: every failed check
1887
+ * / counts against the invite whoever sends it, the fifth voids it (the refusal says so, and the
1888
+ * / record gets `agent.invite.void`), and after that every attempt with it is refused
1889
+ * / `#Conflict` before any check is made (`InviteFailures`).
1890
+ * /
1891
+ * / ⟨RESHAPED 2026-09-29, review finding LIFE-3⟩ The reply is `Types.Pairing`: the agent
1892
+ * / record AND `trackRecord`, which says plainly when the registry refused or failed to record the
1893
+ * / engagement on the agent's track record, and what to do. Before, the reply was `#Ok` with the
1894
+ * / record alone even when the registry had refused the start, so the agent was never told.
1895
+ */
1896
+ pairAgent: ActorMethod<[{ enrolment: Enrolment; code: string }], Result_19>;
1897
+ /**
1898
+ * / ⟨0.16.0, L2.2 — renamed from `guardianPauseWrites`⟩ Same correction as freezePayments above:
1899
+ * / owner-or-guardian, and `resumeWrites` never carried the prefix either.
1900
+ */
1901
+ pauseWrites: ActorMethod<[], Result_1>;
1902
+ /**
1903
+ * / What condensing through `toSeq` would do, and whether it is unlocked. COMMITS NOTHING — it is
1904
+ * / a query, so it structurally cannot; a preview that wrote would be its own trap.
1905
+ * /
1906
+ * / It does not ask the library, because the library's refusal cannot answer the owner's question.
1907
+ * / `Chain.prepareCondense` reports `lastExported = null` whenever the only receipts present are
1908
+ * / author-FILTERED, since a filtered receipt never satisfies the gate and is never recorded as a
1909
+ * / near-miss — and an owner who exported minutes ago would read that as "you have never
1910
+ * / exported". So `filteredReceiptsSeen` is counted separately, and `maxUnlockableToSeq` says how
1911
+ * / far the receipts already on file reach, so a console can offer that instead of only "no".
1912
+ * /
1913
+ * / `maxUnlockableToSeq` is a maximum over every retained unfiltered receipt, and a NEWER receipt
1914
+ * / may cover a SHORTER range than an older one — so the scan cannot stop at the first hit. It is
1915
+ * / bounded by entry count instead, and `scannedFromSeq` / `scanTruncated` say where it stopped
1916
+ * / and whether the bound was the reason. A bounded scan that hid its bound would report "no
1917
+ * / receipts" for "I did not look far enough", which is this codebase's own defect class.
1918
+ * /
1919
+ * / `unlocked` is the export-receipt gate ONLY. It is not a promise the condense will land: the
1920
+ * / history-budget delta is checked at commit time and can still refuse a short prefix.
1921
+ */
1922
+ previewCondense: ActorMethod<[bigint], Result_18>;
1923
+ /**
1924
+ * / A quote for a session this caller has not opened and is not committed to — the intent a
1925
+ * / buyer signs against. Pure dry run, no state, no funds.
1926
+ * /
1927
+ * / PUBLIC: a price list nobody can read is not a price list. A buyer has to see the deposit
1928
+ * / minimum and per-call cost BEFORE signing anything, and gating the quote behind a role would
1929
+ * / mean the only way to learn this engram's price is to already be permitted to pay it.
1930
+ * /
1931
+ * / ⟨CORRECTED 2026-08-24 — this said "⟨L7⟩ UPDATE, NOT QUERY" and cited a market ruling that
1932
+ * / DEC-107 had already closed.⟩ QUERY, per the ruled quote convention: FAST READS. Both
1933
+ * / `quotePayment` and `previewOpenSession` become queries, and L7's open-ruling exception
1934
+ * / retires with them — so the argument written here for keeping it an update was arguing the
1935
+ * / losing side of a decision already made, and was added the same day by not reading forward
1936
+ * / to the ruling. `gate.offerSession` is pure — it validates the intent and returns it — so
1937
+ * / nothing forced the update in the first place.
1938
+ * /
1939
+ * / ONE-REPLICA CAVEAT, stated here because the ruling requires it at both sites: a query is one
1940
+ * / replica's word and is NOT a settleable challenge. Nothing quoted here can be redeemed. The
1941
+ * / commitment happens in `openSession`, which IS a certified update call, and a buyer who needs
1942
+ * / the price attested rather than quoted takes it from that reply.
1943
+ * /
1944
+ * / ⟨RESTORED 2026-08-24, owner ruling R-A1⟩ Named to match the market's, because it is the
1945
+ * / same act against a different seller and a reader comparing the two should not have to learn
1946
+ * / two verbs for it.
1947
+ * /
1948
+ * / ⟨2026-10-02⟩ Answers the house `Types.SessionIntent` — ic402's intent with `expiry` spelled
1949
+ * / `expiryNs`. Same value, same meaning; only the name carries the unit now.
1950
+ */
1951
+ previewOpenSession: ActorMethod<[], SessionIntent>;
1952
+ /**
1953
+ * / Read one memory file at its current version.
1954
+ * /
1955
+ * / Gated on the `read_memory` permission, so an agent holding that grant reaches it — unlike
1956
+ * / `writeMemory`, which is owner-only.
1957
+ * /
1958
+ * / ⚠ `config/` AND `secrets/` ARE OWNER-ONLY whatever the grant says, and the refusal is
1959
+ * / `#Refused` rather than `#Invalid` deliberately: the path is well-formed and the file may well
1960
+ * / exist — the caller simply may not have it. Under L1 that distinction is the caller's to branch
1961
+ * / on, which is the whole reason `Error` is a closed variant rather than a sentence.
1962
+ * /
1963
+ * / ⚠ A QUERY, so it does NOT count as a read. The IC discards query-path state changes, so a
1964
+ * / counter here could never persist; read counting lives on the update path
1965
+ * / (`sessionReadContext` and the MCP reads). A caller measuring engram usage from this method
1966
+ * / will measure nothing.
1967
+ */
1968
+ readMemory: ActorMethod<[string], Result_11>;
1969
+ /**
1970
+ * / Read many paths in one call. Per-path Results are KEPT — partial success is the point, and
1971
+ * / one unreadable path must not fail the other nine.
1972
+ * /
1973
+ * / ⟨0.16.0⟩ The OUTER envelope is new, and it fixes two ways this used to answer dishonestly:
1974
+ * /
1975
+ * / · Over the path cap it returned `[("", #Err(#Invalid …))]` — ONE row, for a path the caller
1976
+ * / never asked about. A consumer looping rows saw a result for the empty path and no result
1977
+ * / for any real one. The call as a whole failed; dressing that as a per-path outcome is the
1978
+ * / fabrication ADR-0002 is about.
1979
+ * / · An AUTHORIZATION refusal was fanned out across every requested path, so one "no" arrived
1980
+ * / as N per-path noes and read like N independent permission facts about N files.
1981
+ * /
1982
+ * / Both are now what they are: a single `#Err` for the whole call. `#Ok` still carries a row per
1983
+ * / path, each with its own Result — a refused RESERVED path sits beside a readable one, which is
1984
+ * / a genuine per-path fact.
1985
+ */
1986
+ readMemoryBatch: ActorMethod<[Array<string>], Result_17>;
1987
+ /**
1988
+ * / ⟨0.16.0⟩ `getMemoryRetentionGuards` DELETED — folded into `getMemoryRetentionPolicy` above.
1989
+ * / It was the second L2.1 array-returning `get*`, and separating it from the policy it modifies
1990
+ * / was the defect described there. Its own docs are preserved at the fold site.
1991
+ * / One page of a file's content — the paged read the whole-file surfaces point at.
1992
+ * /
1993
+ * / `version = null` reads the live file; a version reads that version as it was recorded.
1994
+ * / The store clamps a page to one chunk, and `more` DISCLOSES the clamp: a caller that cannot
1995
+ * / see it cannot know whether it has the whole range, which is how silent truncation gets
1996
+ * / reintroduced. Loop while `more` is true, advancing by the bytes actually returned.
1997
+ */
1998
+ readMemoryBytes: ActorMethod<[string, bigint, bigint, [] | [bigint]], Result_16>;
1999
+ /**
2000
+ * / The escrow exit for a session whose settle cannot pay.
2001
+ * /
2002
+ * / PAYER-ONLY, enforced inside the gateway, and deliberately not owner-triggered: the payer's own
2003
+ * / deposit is the only thing here, so making them wait for anyone else would be a worse rail than
2004
+ * / the one this replaces. (The market's twin is admin-triggered because a marketplace session has
2005
+ * / a counterparty; a memory session does not.)
2006
+ * /
2007
+ * / WHY IT IS NEEDED AT ALL: `closeSessionInternal` settles only when
2008
+ * / `deposited >= consumed + fee`, and vouchers may consume up to the full deposit — so a payer
2009
+ * / who spends their whole budget makes their own session unsettleable, with no adversary
2010
+ * / involved. Before this, the refusal text told them to call `recoverEscrow`, which existed on no
2011
+ * / canister they could reach. RB2 caps consumable spend so ordinary use cannot reach that state;
2012
+ * / this is the way back for a session that already has.
2013
+ * /
2014
+ * / ⟨CORRECTION 2026-09-30, beside the paragraph above and the first line⟩ No longer true. ic402
2015
+ * / 2.17.0's `closeSessionInternal` settles `min(consumed, deposited − fee)` and skips a refund of
2016
+ * / zero, so a session spent to its whole budget still closes, and under the one-fee reserve a clean
2017
+ * / close leaves the escrow holding nothing or less than one fee, which no transfer can move. The
2018
+ * / way back is for a REFUND LEG THAT FAILED (a transient ledger error): the settle went through,
2019
+ * / ic402 marks the session closed, and the remainder stays in escrow until the payer calls this.
2020
+ * / A failed settle is not this method's case: ic402 puts that session back to open, where this
2021
+ * / method refuses, and the close is retried instead. WHAT WOULD MAKE THIS WRONG: an ic402 whose
2022
+ * / close stops capping the settle, or a live ckUSDC fee above `Env.CKUSDC_FEE`.
2023
+ * /
2024
+ * / ckUSDC only — an engram session's intent names `Env.CKUSDC_LEDGER` and nothing else, so there
2025
+ * / is no token to choose and no wrong one to pass.
2026
+ * /
2027
+ * / ⟨2026-10-02, decided — the twin divergence is deliberate⟩ The market's `recoverEscrow` takes
2028
+ * / `Wire.TokenAmount`; this one takes a bare `nat`, and the two stay different on purpose. The
2029
+ * / market escrows more than one token, so the amount has to say which; this engram's sessions
2030
+ * / escrow ckUSDC only, and a `TokenAmount` here would make an `#Icp` amount representable and then
2031
+ * / refuse it at runtime — the argument `convertEarningsToCycles` makes. What changed is the NAME:
2032
+ * / `amountE6`, ckUSDC base units. Candid passes arguments by position, so nothing on the wire moved.
2033
+ * /
2034
+ * / ⚠ `#Conflict` HERE ALSO COVERS "NOT THE SESSION'S PAYER". ⟨2026-10-02, audited at this site⟩
2035
+ * / The payer check is ic402's (`recoverEscrow` authorizes `caller == session.payer`), and the
2036
+ * / library answers every refusal down one text channel, so "Not authorized: only session payer can
2037
+ * / recover escrow" arrives as `#Conflict`, beside the state refusals (an open session, nothing to
2038
+ * / recover, no such session). Read the MESSAGE, not the arm. This is the 0.16.0 contract as
2039
+ * / ratified on 2026-10-02; giving the library one arm per kind of refusal is post-cut dependency
2040
+ * / work. (The payments-frozen refusal in the body is this engram's own, and is state.)
2041
+ * /
2042
+ * / ⟨2026-10-05, ic402 2.17.3 — beside the list above⟩ A fourth state refusal: a session that reads
2043
+ * / `closing` or `expired`, whose close has not finished. Escrow comes back only from a session that
2044
+ * / reads `closed`, and the refusal moves nothing. A close that stopped part-way (its refund call
2045
+ * / rejected, or a trap) leaves the session reading `closing`, and no method on this engram moves it.
2046
+ */
2047
+ recoverEscrow: ActorMethod<[string, bigint], Result_8>;
2048
+ /**
2049
+ * / ⟨0.16.0, L1⟩ A REDEMPTION PATH, where the arm choice is a disclosure decision.
2050
+ * /
2051
+ * / Four of these refusals are about the CODE and one is about the caller. The code arms restate
2052
+ * / exactly what the text already said — an unknown code is `#NotFound`, a used or expired one is
2053
+ * / `#Conflict` — so no fact is newly disclosed by the arms; the anti-enumeration control here is
2054
+ * / the attempt throttle above, not vagueness in the reply. Throttling is itself `#Conflict` (at
2055
+ * / capacity) rather than `#Unavailable`: nothing failed, and the caller's own recent behaviour is
2056
+ * / what closed the door, so "try again" is true only after the stated wait.
2057
+ * /
2058
+ * / ⟨2026-10-02⟩ Answers the `GuardianRecord` it created — `#Pending` until the owner approves —
2059
+ * / rather than `()`. The new guardian learns, in the same reply, the name and permissions the
2060
+ * / owner's invite gave them and that they cannot act until approved; before, that took a second
2061
+ * / read they had no reason to know to make.
2062
+ */
2063
+ registerGuardian: ActorMethod<[string], Result_15>;
2064
+ /**
2065
+ * / Remove a per-caller override so that caller reverts to — and keeps TRACKING — the global caps.
2066
+ * /
2067
+ * / It travels with its pair and is never dropped alone: without it the only way "back" from an
2068
+ * / override is to overwrite it with a frozen copy of the global policy, which then stops
2069
+ * / following later changes. That makes every override permanent in effect.
2070
+ */
2071
+ removeCallerSpendPolicy: ActorMethod<[Principal], Result_1>;
2072
+ /**
2073
+ * / De-register a type that has NEVER SIGNED. Exists because of a hazard the first external
2074
+ * / validation found within hours (consumer report, 2026-08-06): a bare-name #standard registration —
2075
+ * / cheap, no watcher preconditions — permanently blocked the guarded namespaced registration
2076
+ * / via the collision rule, with no way out. An owner typo could brick a venue integration for
2077
+ * / the engram's lifetime. Never-signed is the whole gate: a type that signed even once is part
2078
+ * / of what the audit chain's eip712.sign entries mean, and stays resolvable forever — this
2079
+ * / removes only authority that was never exercised, which is removing nothing but the mistake.
2080
+ * / NOT freeze-gated, same reasoning as removeEvmWithdrawDestination: this is TIGHTENING, and a
2081
+ * / frozen engram must still be able to shrink what it could sign.
2082
+ */
2083
+ removeEip712Type: ActorMethod<[Uint8Array | number[]], Result_1>;
2084
+ removeEvmWithdrawDestination: ActorMethod<[string], Result_1>;
2085
+ /**
2086
+ * / Owner-only: remove a guardian from the roster.
2087
+ * /
2088
+ * / Unlike revoking an agent this is NOT terminal for the principal — the guardian roster does
2089
+ * / not carry the one-shot rule that blocks a revoked agent from ever pairing again, so the
2090
+ * / same wallet can be invited again.
2091
+ * /
2092
+ * / `#NotFound` rather than `#Refused` when there is no such guardian: only the owner reaches this
2093
+ * / line, so the roster is theirs and its contents are not a secret being withheld from them.
2094
+ */
2095
+ removeGuardian: ActorMethod<[Principal], Result_1>;
2096
+ /**
2097
+ * / Owner disavows a specific memory write, in the open. Marks — never deletes: the content and
2098
+ * / the original audit entry stay exactly where they were; this appends a chained
2099
+ * / `memory.repudiate` entry and lists the (path, version) so readers can see the dispute.
2100
+ */
2101
+ repudiateMemoryWrite: ActorMethod<[string, bigint, string], Result_8>;
2102
+ /**
2103
+ * / ⚠ OWNER-ONLY BULK RESET. Destructive, and wider than its name suggests.
2104
+ * /
2105
+ * / It severs EVERY grant surface that can outlive a role — agents, guardians, invites and
2106
+ * / connector tokens — clears memory, and returns the operational flags (encryption, writes-paused,
2107
+ * / payments-frozen) to a fresh baseline. Anyone holding access through any of those loses it.
2108
+ * /
2109
+ * / What SURVIVES, deliberately:
2110
+ * / · the cumulative counters, which never reset — an engram cannot make itself look new;
2111
+ * / · memory DELETES are soft, so version history is retained and paths stay enumerable via
2112
+ * / `listDeletedMemoryFiles`;
2113
+ * / · `agentPurgeLog`, which is the durable record of who was severed;
2114
+ * / · ⟨2026-09-29⟩ today's spending totals — each caller's and the engram-wide one — and the
2115
+ * / owner's engram-wide ceiling. A reset severs access; it never gives back a day's allowance
2116
+ * / already spent, so a key re-admitted after a reset keeps what it spent today (the totals are
2117
+ * / kept per calling key).
2118
+ * / · ⟨2026-10-02⟩ the seat weeks of every engagement (`agentSeatWeeks`), with the signature count
2119
+ * / they sit beside, and the owner's switch over the metrics reader's read and the reader it
2120
+ * / names — a reset severs access, it does not change who may read what was kept.
2121
+ * /
2122
+ * / ⟨2026-10-02⟩ It tells the spawning registry that it happened (`sysNoteReset`), on every reset.
2123
+ * /
2124
+ * / It is recorded as ONE chained `engram.reset` entry that also names the flag transitions.
2125
+ * /
2126
+ * / ⚠ AND THE LIMIT OF THAT RECORD, because a caller relying on it should know: the audit chain is
2127
+ * / NOT unbounded. It caps at MAX_ENTRIES and trims its oldest tenth on overflow, so on any engram
2128
+ * / long-lived enough for the rent model to apply, the reset entry is not guaranteed to still be
2129
+ * / there. `agentPurgeLog` is the evidence that does not age out — which is why it exists.
2130
+ */
2131
+ resetEngram: ActorMethod<[], Result_14>;
2132
+ /**
2133
+ * / ⟨2026-09-28, owner decision: an agent can resign from an engram, and the resignation is
2134
+ * / recorded⟩ The AGENT ends its own engagement with this engram.
2135
+ * /
2136
+ * / WHY IT EXISTS: before this, every ending was something done TO an agent — revoked by the
2137
+ * / owner, by a guardian, by the kill switch, or by a reset — so an agent that wanted to leave
2138
+ * / cleanly had to wait to be fired, and its track record across engrams could not tell a clean exit
2139
+ * / from a firing. This is the one ending the agent itself chooses, and the registry records it
2140
+ * / under its own reason (`#Resigned`), never folded into a revocation.
2141
+ * /
2142
+ * / TERMINAL for this principal on this engram, exactly like a revocation: the record stays (status
2143
+ * / `#Resigned`, auditable), and `pairAgent` refuses any principal that already holds a
2144
+ * / record, so returning means a different principal and a fresh invite from the owner.
2145
+ * /
2146
+ * / SELF-SERVICE, so the refusals are about the record's state, not the caller's standing:
2147
+ * / `#NotFound` for a caller that is not an agent here, `#Conflict` for one already ended.
2148
+ * / The roster change and its chained audit line commit BEFORE the registry is told, so a registry
2149
+ * / that is down cannot leave the agent half-resigned; a missed notice is logged by
2150
+ * / `notifyRegistryAgentEdge`. WHAT WOULD MAKE THIS WRONG: a second path that sets `#Resigned`.
2151
+ */
2152
+ resignAgent: ActorMethod<[], Result_1>;
2153
+ /**
2154
+ * / OWNER-ONLY release of the write pause, with the same one-way shape as `unfreezePayments`: a
2155
+ * / guardian holding `canPauseWrites` can stop writes without the owner and cannot restart them,
2156
+ * / and the owner can always restart them. A tripwire rather than a lock.
2157
+ */
2158
+ resumeWrites: ActorMethod<[], Result_1>;
2159
+ /**
2160
+ * / Self-heal: re-send every ACTIVE agent's start to the spawning registry (idempotent — the
2161
+ * / registry mints no duplicate for an open engagement), for when a notice was missed. Owner-only.
2162
+ * / Returns how many the registry ACKNOWLEDGED. ⟨2026-09-28: it used to count sends that did not
2163
+ * / throw, against a method that could not say no; it now counts `#Ok` answers.⟩ It re-sends
2164
+ * / starts only: an ending carries a reason this roster does not keep per principal.
2165
+ * /
2166
+ * / ⟨CORRECTED 2026-09-29, review finding LIFE-2 — owner's option A⟩ It now re-sends ENDINGS as
2167
+ * / well as starts, endings first (`AgentEdges.resyncPlan` says why): every ended record on the
2168
+ * / roster and every agent a reset removed keeps its ending's reason and day
2169
+ * / (`Types.AgentEnding`), so an ending the registry never received — the one loss that used to
2170
+ * / show an engram's engagement as live on the agent's record forever and block the agent's later starts here —
2171
+ * / is recorded by one call of this. The registry answers an ending it already holds `#Ok`.
2172
+ * / RESHAPED REPLY: `Types.ResyncReport` in place of a bare count — the endings and starts the
2173
+ * / registry acknowledged, and every notice it did not, with its own words, so the owner can tell
2174
+ * / an expected answer (an ending for a start that was never recorded says so) from a real one.
2175
+ * / The calls leave in batches of `RESYNC_BATCH`, each batch in order and wholly answered before the
2176
+ * / next leaves, so the order above holds at the registry.
2177
+ * / ⟨2026-09-29⟩ WHAT A RESYNC CANNOT DO: record an engagement whose start the registry never
2178
+ * / recorded and which has since ENDED. A start is re-sent only for an agent still active here, so
2179
+ * / all that is left to send is the ending, and the registry has nothing to end. The report lists
2180
+ * / each such engagement under `cannotBeRecorded` (key, root, invite, and how and when it ended),
2181
+ * / apart from `notRecorded`, so the owner sees them rather than silence.
2182
+ */
2183
+ resyncAgentEdges: ActorMethod<[], Result_13>;
2184
+ /**
2185
+ * / Return to managed custody: the engram adds the registry back as a controller ALONGSIDE the
2186
+ * / owner — it does not remove the owner. The inverse of `claimSovereignty`, and the reason
2187
+ * / sovereignty is not a one-way door.
2188
+ */
2189
+ returnToManaged: ActorMethod<[], Result_1>;
2190
+ /**
2191
+ * / Replace the whole content of an EXISTING file.
2192
+ * /
2193
+ * / This is the one thing agents could never do before: every agent write was an append,
2194
+ * / so a file could only ever grow. The ruling that opened it is narrow, and every part of the
2195
+ * / narrowness is enforced below — an agent may replace content only on a path the owner has
2196
+ * / granted, only where retention is not #vault, and only where the file already exists. Vault
2197
+ * / paths stay append-only forever, which is the claim the product makes about them.
2198
+ * /
2199
+ * / Replacing is safe here in a way it was not in the legacy store: the prior version is not
2200
+ * / overwritten, it is superseded. It stays readable, its hash stays committed, and the agent
2201
+ * / floor keeps its bytes for the window a counterparty needs to extract them.
2202
+ * / ⟨0.16.0, L1⟩ FIVE AGENT REFUSALS, ALL `#Refused`, AND THE UNIFORMITY IS THE FINDING.
2203
+ * /
2204
+ * / Reserved path, protected path, missing permission, ungranted revise path, `#vault` class — a
2205
+ * / caller could previously tell these apart only by reading five different sentences, and every
2206
+ * / one of them ends the same way: this agent may not make this write, and no retry by this
2207
+ * / agent changes that. The prose already said "Not operator-retryable" four times over,
2208
+ * / because a text field was the only place to put it. It is an arm now.
2209
+ * /
2210
+ * / The one that could tempt a different arm is `#vault`, which looks like a state fact. It is
2211
+ * / not: the class is an AUTHORIZATION statement about who may replace content there, and it
2212
+ * / resolves to the same "you may not", forever, for everyone but the owner.
2213
+ */
2214
+ reviseMemory: ActorMethod<[string, Uint8Array | number[]], Result>;
2215
+ /**
2216
+ * / Owner-only: revoke one agent.
2217
+ * /
2218
+ * / ⚠ SOFT AND TERMINAL, which sounds contradictory and is not. The record is not deleted — the
2219
+ * / status becomes `#Revoked` and the row survives, which is what makes the revocation auditable.
2220
+ * / And because `pairAgent` refuses any principal that already holds a record of ANY
2221
+ * / status, this is permanent FOR THAT PRINCIPAL: they cannot be re-invited. Re-admitting the same
2222
+ * / human means a different wallet.
2223
+ * /
2224
+ * / To narrow what an agent may do rather than end its access, use `setAgentPermissions`.
2225
+ */
2226
+ revokeAgent: ActorMethod<[Principal], Result_1>;
2227
+ /**
2228
+ * / Owner-only panic button: revoke EVERY active agent at once. Returns how many were revoked.
2229
+ * /
2230
+ * / ⚠ IT REVOKES ONLY AGENTS. Invites and connector bearer tokens are separate surfaces with
2231
+ * / their own buttons (`revokeAllInvites`, `revokeAllBearerTokens`), and an owner reaching for one
2232
+ * / of these in an emergency almost certainly wants all three. Nothing here cascades.
2233
+ * /
2234
+ * / ⚠ AND IT IS IRREVERSIBLE PER PRINCIPAL, which a "revoke all" reads as temporary and is not.
2235
+ * / Each agent's record is set to `#Revoked` rather than deleted, and `pairAgent`
2236
+ * / refuses any principal holding a record of ANY status — so every wallet this touches can never
2237
+ * / be an agent on this engram again. Re-admitting the same agents means new keys. Only
2238
+ * / `resetEngram` clears the records, and it severs everything else with them.
2239
+ * /
2240
+ * / The revocation is committed BEFORE the registry is told: state is cleared, the audit line is
2241
+ * / written, and only then does it await one notification per revoked agent. So a notification
2242
+ * / that fails leaves the agents revoked here regardless — a partial notify is not a partial
2243
+ * / revocation, which is the direction that matters for a panic button.
2244
+ */
2245
+ revokeAllAgents: ActorMethod<[], Result_8>;
2246
+ /**
2247
+ * / Owner-only panic button: revoke every connector bearer token at once. Returns how many.
2248
+ * /
2249
+ * / The THIRD independent surface — hosted connectors authenticate with bearer tokens, not with
2250
+ * / agent records or invites, so neither of the buttons above touches them. An owner cutting
2251
+ * / off access completely needs all three, and this is the one that reaches an AI host already
2252
+ * / holding a live session.
2253
+ * /
2254
+ * / Tokens are re-issuable: revoking them is not permanent the way revoking an agent is.
2255
+ */
2256
+ revokeAllBearerTokens: ActorMethod<[], Result_8>;
2257
+ /**
2258
+ * / ⟨0.16.0⟩ `removeAllGuardians` DELETED — test-only (L6), and verified NOT part of KILL-SWITCH's
2259
+ * / mass-revoke set. The destructive phase-07 suite iterates `removeGuardian` instead, so nothing
2260
+ * / loses a capability: what dies is a bulk spelling no runbook ever invoked.
2261
+ * / Owner-only panic button: void every unredeemed invite. Returns how many were voided.
2262
+ * /
2263
+ * / Separate from `revokeAllAgents`: this stops invites that have NOT been redeemed yet and
2264
+ * / touches no existing agent. An invite already redeemed is an agent, and only the other
2265
+ * / button reaches it.
2266
+ * /
2267
+ * / Unlike revoking an agent, this costs nothing permanently — an invite is a one-time code,
2268
+ * / so voiding it and minting a fresh one is the ordinary path.
2269
+ */
2270
+ revokeAllInvites: ActorMethod<[], Result_8>;
2271
+ /**
2272
+ * / Revoke a bearer token by its public tokenId. Idempotent.
2273
+ * / Subsequent /mcp requests using this token will be rejected.
2274
+ */
2275
+ revokeBearerToken: ActorMethod<[string], Result_1>;
2276
+ /**
2277
+ * / ⟨0.16.0, census §10 item 16⟩ RETURNS A REAL RECEIPT, not `R<()>` — same reason as the delete
2278
+ * / above, and sharper here: a rollback WRITES A NEW VERSION, so the caller's next question is
2279
+ * / always "which version am I on now". `r.version` was already read for the audit line.
2280
+ */
2281
+ rollbackMemory: ActorMethod<[string, bigint], Result>;
2282
+ /**
2283
+ * / SELF-SERVICE, and that is the surprising part: the AGENT calls this, not the owner. An
2284
+ * / agent rotates its own CallerKey binding without needing the owner to act.
2285
+ * /
2286
+ * / ⚠ IT ROTATES THE KEY, NOT THE PRINCIPAL. Only `publicKeyHash` changes; the agent record
2287
+ * / stays keyed on the same principal, keeps its permissions, and keeps its place against the
2288
+ * / one-shot registration rule. So this is the answer to "my key is compromised", and it is NOT a
2289
+ * / way to move an agent seat to a different wallet — that is a new invite, and only if the
2290
+ * / old principal was never revoked.
2291
+ * / ⟨CORRECTED 2026-09-29, the owner's ruling of that date (follow-up 10, option A)⟩ Two sentences
2292
+ * / above are no longer true. An agent's record CAN now move to a different key, in one step and
2293
+ * / with no new invite: `nominateAgentKey` from the current key, then `acceptAgentKeyNomination`
2294
+ * / from the new one. And a compromised key is answered by that move — this method only changes a
2295
+ * / recorded hash, and the compromised principal keeps calling as the agent. This method still
2296
+ * / does what it says; the move is the one that changes which key the engram answers.
2297
+ * /
2298
+ * / `#Conflict` rather than `#Refused` for a `#Revoked` or `#Resigned` record: the caller IS the
2299
+ * / agent on that record, so its standing is not the problem — the record's state is. An
2300
+ * / agent reading `#Refused` would go looking for a permission that was never missing.
2301
+ */
2302
+ rotateAgentKeyHash: ActorMethod<[string], Result_1>;
2303
+ /**
2304
+ * / One-time onboarding seed: writes a starter file so the first read-back is non-empty.
2305
+ * /
2306
+ * / Owner-only, and it REFUSES once any memory exists — so it can only ever add the initial
2307
+ * / placeholder and can never overwrite real content. Deliberately NOT counted as a write (no
2308
+ * / `totalMemoryWrites`, no `firstWriteAt`): it is a system seed rather than activity, and
2309
+ * / counting it would corrupt both the write metrics and time-to-first-write for every engram.
2310
+ */
2311
+ seedMemory: ActorMethod<[string, Uint8Array | number[]], Result>;
2312
+ /**
2313
+ * / Append to a memory file against a PAID x402 session voucher — the write half of the paid rail,
2314
+ * / authorized by the voucher rather than by a role.
2315
+ * / ⟨2026-09-30, ic402 2.17.0⟩ Authorized by the payer's own call with the voucher: only the
2316
+ * / principal that opened the session, calling as that key, can spend it (see `sessionReadMemory`).
2317
+ * / ⟨CORRECTED 2026-09-30, the owner's answer "2 fresh key"⟩ Authorized by the session KEY's own
2318
+ * / call: the fresh key the payer named at open. The write is attributed to the payer, who paid;
2319
+ * / the record row also names the key that made it.
2320
+ * /
2321
+ * / ⚠ AS WITH `sessionReadMemory`, EVERY REFUSAL FIRES BEFORE THE VOUCHER IS CONSUMED — nothing is
2322
+ * / written and no funds move. It refuses when payments are frozen, when writes are PAUSED, and
2323
+ * / when the engram is client-side encrypted: a paid session appending plaintext to an encrypted
2324
+ * / store would CORRUPT it, so that refusal is protecting the owner's data rather than gating
2325
+ * / access. Append through the EngramX client/SDK instead.
2326
+ * / ⟨API-101/DEC-101, 2026-08-24 — v3 phase X3⟩ RETURNS THE SAME RECEIPT THE FREE WRITER DOES.
2327
+ * / It answered `Wire.Result<Nat>`: the version, and nothing else. The free `writeMemory` returns
2328
+ * / `{ version; seq; head }`, so a PAYING writer got strictly LESS evidence than a caller who paid
2329
+ * / nothing — on the one rail a stranger can buy, where the receipt is the whole product. The head
2330
+ * / is what makes an append verifiable by someone who was not there; a bare version number is not
2331
+ * / checkable against anything.
2332
+ * /
2333
+ * / It cost nothing to fix: `r` was already in scope and already being read — the old body did
2334
+ * / `let v = r.version` and passed `r` to `receiptSuffix(r)` for the audit line, then discarded
2335
+ * / everything but the version on the way out. Free until the cut, breaking forever after, which
2336
+ * / is why it lands now rather than after the test migration (ruling R-A2).
2337
+ */
2338
+ sessionAppendMemory: ActorMethod<[Voucher, string, Uint8Array | number[]], Result>;
2339
+ /**
2340
+ * / The whole engram in one call — newest-first, byte-capped — for an AI host to inject at session
2341
+ * / start. The "read me back" that continuity is built on. `clientLabel` names the reading host
2342
+ * / (e.g. "openclaw", "claude.ai") for the distinct-reader set.
2343
+ * /
2344
+ * / ⚠ AN UPDATE, NOT A QUERY, AND ON PURPOSE (L7). `readMemory`/`readMemoryBatch` are queries and
2345
+ * / therefore CANNOT persist a read count; this runs on the update path and bumps the reuse
2346
+ * / counters, so a builder whose SDK calls `startSession()` registers a weekly-reused engram as a
2347
+ * / byproduct of normal use rather than through an elective, separate read. Callers should expect
2348
+ * / update latency and consensus cost here, and get a recorded read in exchange.
2349
+ * /
2350
+ * / ⚠ IT DOES NOT RETURN EVERYTHING, and the omission is deliberate: `config/` and `secrets/` are
2351
+ * / SKIPPED. Those are operational, not agent memory, and must never be blindly spilled into a
2352
+ * / model's context window — so a caller must not treat this as a complete listing of the engram.
2353
+ * /
2354
+ * / ⚠ RAW STORED BYTES, like `readMemoryBatch`. On a Private (encrypted) engram the content is
2355
+ * / CIPHERTEXT; the key-holding SDK decrypts it. A caller without the key gets bytes it cannot
2356
+ * / read, not an error.
2357
+ */
2358
+ sessionReadContext: ActorMethod<[string], Result_12>;
2359
+ /**
2360
+ * / Read one memory file against a PAID x402 session voucher. No role, no invite — the voucher is
2361
+ * / the authorization, which is what makes this the engram's one rail a stranger can pay to use.
2362
+ * /
2363
+ * / ⟨2026-09-30, ic402 2.17.0⟩ WHO MAY SPEND A SESSION: only its payer, calling as the same raw
2364
+ * / Ed25519 key that opened it. The voucher still carries the amount and the sequence; the
2365
+ * / authorization is now the call itself, and the canister no longer checks a voucher signature.
2366
+ * / A stranger can still pay to use this rail — by opening a session of their own.
2367
+ * / ⟨CORRECTED 2026-09-30, the owner's answer "2 fresh key"⟩ Not the payer: the session's own key
2368
+ * / — the fresh Ed25519 key the payer named at open — calling as itself. The payer, who opened
2369
+ * / the session and closes it, is refused here like anyone else who is not that key.
2370
+ * / ⟨CORRECTED 2026-09-30, review⟩ …unless the payer named their own identity key at open, which
2371
+ * / nothing refuses: then the payer IS that key and spends.
2372
+ * /
2373
+ * / ⚠ EVERY REFUSAL BELOW HAPPENS BEFORE THE VOUCHER IS CONSUMED, so **no funds move on any of
2374
+ * / them**. That is the property a payer most needs and the one a signature cannot express: a
2375
+ * / refusal here costs nothing, and retrying after the owner changes something costs nothing extra.
2376
+ * /
2377
+ * / It refuses when:
2378
+ * / · **Paid reads are not enabled — and they are OFF BY DEFAULT.** Selling the owner's memory to
2379
+ * / any voucher-bearer is a deliberate choice, not a default posture, so on a fresh engram this
2380
+ * / is the refusal you will get. `getEngramCard`'s `x402Support` reports this same flag, so a
2381
+ * / buyer can check before paying rather than discover it here.
2382
+ * / · **The engram is Private (client-side encrypted).** A paid session holds no key and the
2383
+ * / canister never decrypts, so it could only return ciphertext. Read through the EngramX
2384
+ * / client/SDK instead — this is not a permission problem and no setting fixes it.
2385
+ * / · **The path is `config/` or `secrets/`.** Owner-only on every other surface, and a paid
2386
+ * / session must not be the side door: without this guard a stranger holding a fraction-of-a-
2387
+ * / cent voucher could read `secrets/*`.
2388
+ * / · Payments are frozen on this engram.
2389
+ */
2390
+ sessionReadMemory: ActorMethod<[Voucher, string], Result_11>;
2391
+ /**
2392
+ * / Configure action alerts: an https webhook that receives new chained-audit entries matching the
2393
+ * / enabled event classes (money / approvals / guardian / agentWrites), batched, at most one
2394
+ * / POST per minute. Owner-only. Payloads carry audit METADATA (operation, caller, role, bounded
2395
+ * / details) — never memory file contents. Setting a URL (re)arms delivery FROM NOW: the cursor
2396
+ * / jumps to the current end of the log so history is not replayed. Passing url = null disables.
2397
+ * / The URL itself is never written to the audit log (webhook URLs often embed secret tokens).
2398
+ */
2399
+ setActionAlertConfig: ActorMethod<[AlertConfig], Result_1>;
2400
+ /**
2401
+ * / Owner-only: replace an existing agent's permission set. The way to NARROW what an agent
2402
+ * / may do without ending their access — `revokeAgent` is terminal for that principal, this is
2403
+ * / not.
2404
+ * /
2405
+ * / ⚠ ONE GRANT IS REFUSED OUTRIGHT: memory-read to the EngramX PLATFORM principal while this
2406
+ * / engram is Private (encrypted), because that principal could then derive the decryption key and
2407
+ * / Private mode would be a claim rather than a property. It is the mirror of the guard on
2408
+ * / `setEncryptionEnabled`, which refuses to ENABLE Private while that grant already exists —
2409
+ * / between them the invariant holds whichever order an owner works in.
2410
+ * /
2411
+ * / That refusal is `#Refused` ABOUT THE SUBJECT, not about the caller: the owner is authorized
2412
+ * / and the grantee is not eligible. It is standing rather than a conflict to resolve, so the way
2413
+ * / forward is to grant read to your own agents instead, or to switch to Connected mode first —
2414
+ * / both of which the message says.
2415
+ */
2416
+ setAgentPermissions: ActorMethod<[Principal, AgentPermissions], Result_1>;
2417
+ /**
2418
+ * / Paths an agent holding a grant may REVISE rather than only append to.
2419
+ * /
2420
+ * / Matching is EXACT, except that an entry ending in "/" grants everything beneath it. A grant
2421
+ * / is a power, so the default reading is the narrow one; the directory form exists because the
2422
+ * / real use case is rotating dated files under a prefix, and per-file grants would be unusable
2423
+ * / for that. What a bare prefix would do — "MEMORY.md" also matching "MEMORY.md.bak" — is the
2424
+ * / kind of accident a permission surface must not have.
2425
+ */
2426
+ setAgentRevisablePaths: ActorMethod<[Array<string>], Result_1>;
2427
+ /**
2428
+ * / ⟨0.16.0 — census row⟩ Returns the APPLIED config, which is how this closes the
2429
+ * / setter-without-a-getter gap without adding a method: the write is the read.
2430
+ * /
2431
+ * / `prunedBackups` is the part that matters. Enforcing a retention cap DELETES finalized backups
2432
+ * / beyond it, and this method used to answer `#Ok(())` over that — the module's own comment
2433
+ * / called it an "ops floor: retention enforcement deletes owner backup data silently", mitigated
2434
+ * / by a `Debug.print` nobody reads. An owner lowering the cap is destroying their own backups;
2435
+ * / they are told how many, in the reply and in the audit line.
2436
+ */
2437
+ setBackupRetention: ActorMethod<[string, bigint], Result_10>;
2438
+ /**
2439
+ * / Override the caps for ONE caller — an agent this owner trusts more, or less, than the rest.
2440
+ */
2441
+ setCallerSpendPolicy: ActorMethod<[Principal, SpendingPolicy], Result_1>;
2442
+ /**
2443
+ * / Owner-only: set how many engrams `agentPrincipal`'s agent may open of its own through this
2444
+ * / engram. Kept by the agent's lasting key, so it carries over a key replacement. Any count is
2445
+ * / accepted; the registry lets a lasting key open one engram through a parent, ever, so 1 or more
2446
+ * / behaves as 1. 0 withdraws it.
2447
+ * /
2448
+ * / APPROVING IS GIVING: what this engram attaches to open an engram (1.3 T cycles) is the agent's
2449
+ * / from the moment that engram exists — the agent's lasting key owns it, and nothing is ever taken
2450
+ * / back. The change is written to the record under `agent.childAllowance.set`, which is in the
2451
+ * / alerts' money class (`ActionAlerts.classify`), so an owner or guardian with an alert channel
2452
+ * / hears of it.
2453
+ */
2454
+ setChildAllowance: ActorMethod<[Principal, bigint], Result_1>;
2455
+ /**
2456
+ * / ⟨0.16.0⟩ `getEncryptedMemoryKeyForEpoch` DELETED — folded into `getEncryptedMemoryKey`'s epoch
2457
+ * / argument — see that method for the fold and the `null`-means-CURRENT rule.
2458
+ * / Owner-only: turn client-side memory encryption (Private mode) on or off for FUTURE writes.
2459
+ * /
2460
+ * / ⚠ IT DOES NOT TOUCH EXISTING FILES, and this is the fact that decides whether calling it alone
2461
+ * / is safe. Verified at the site 2026-08-21: the body sets the flag and writes an audit line —
2462
+ * / there is no migration pass. So
2463
+ * / · turning it ON leaves everything already stored as PLAINTEXT at rest, and
2464
+ * / · turning it OFF leaves everything already stored as CIPHERTEXT, which the hosted connector
2465
+ * / cannot read.
2466
+ * / Either direction leaves a MIXED store that the flag alone misdescribes. The owner console
2467
+ * / pairs this call with a migration (`useMemoryEncryption`'s `migrate` / `migrateToPlaintext`)
2468
+ * / for exactly that reason; a caller reaching this method directly gets the flag and nothing else.
2469
+ * /
2470
+ * / ⚠ ENABLING IS REFUSED while the EngramX platform principal holds memory-read access as an
2471
+ * / agent — it could derive the decryption key, which would make Private mode a claim rather
2472
+ * / than a property. Revoke that agent's read access first. The refusal says so, and it is a
2473
+ * / `#Conflict` rather than a `#Refused` because the caller IS the owner and the problem is the
2474
+ * / engram's state, not their standing.
2475
+ * /
2476
+ * / Private mode also closes the paid read rail by construction: a paid session holds no key, so
2477
+ * / `sessionReadMemory` refuses on an encrypted engram whatever `setPaidMemoryReadEnabled` says.
2478
+ */
2479
+ setEncryptionEnabled: ActorMethod<[boolean], Result_1>;
2480
+ /**
2481
+ * / Register the owner's EVM address for withdrawals.
2482
+ * /
2483
+ * / First set: immediate — no guardian needed.
2484
+ * / Change: only allowed if an active guardian exists (proving the owner
2485
+ * / has a safety net). Without a guardian, the address is locked after
2486
+ * / first set — this prevents a compromised II from silently redirecting
2487
+ * / EVM withdrawals when no one is watching.
2488
+ * /
2489
+ * / The guardian doesn't approve the change — the owner is sovereign.
2490
+ * / The guardian's existence is the gate, not their active consent.
2491
+ */
2492
+ setEvmOwnerAddress: ActorMethod<[string], Result_1>;
2493
+ /**
2494
+ * / A guardian arms their OWN webhook over the guarded engram's audit stream (same event
2495
+ * / classes and payload as the owner channel — audit metadata, never memory file contents;
2496
+ * / the guardian honesty rail: integrity, not content). Active guardians only. Arming starts
2497
+ * / from NOW (no history replay); url = null disarms and frees the slot.
2498
+ */
2499
+ setGuardianAlertConfig: ActorMethod<[AlertConfig], Result_1>;
2500
+ /**
2501
+ * / Per-prefix retention policy. Longest prefix wins; anything unmatched keeps everything.
2502
+ * /
2503
+ * / A CHANGE does not take effect immediately, in EITHER direction: every prefix whose EFFECTIVE
2504
+ * / class moves is guarded for the same window as the agent floor, so history cannot be
2505
+ * / thinned in the same sweep as the decision to thin it. Loosening waits too — distinguishing
2506
+ * / "tightened" from "loosened" precisely would mean comparing two cap lattices, so armGuards
2507
+ * / (RetentionPolicy.mo) guards any change it sees. That is the conservative reading, and its
2508
+ * / only cost is a delay on keeping MORE, which destroys nothing.
2509
+ */
2510
+ setMemoryRetentionPolicy: ActorMethod<[Array<[string, RetentionClassSpec]>], Result_1>;
2511
+ /**
2512
+ * / Owner-only: open or close the monetized read rail. When disabled (the default), sessionReadMemory
2513
+ * / fails closed for every voucher-bearer — selling the owner's memory is opt-in, not the default.
2514
+ * /
2515
+ * / ⚠ ENABLING IT IS NOT SUFFICIENT. On a Private (encrypted) engram `sessionReadMemory` still
2516
+ * / refuses, because a paid session holds no key and the canister never decrypts — see
2517
+ * / `setEncryptionEnabled`. An owner who turns this on and still sees refusals should check that
2518
+ * / flag before looking anywhere else.
2519
+ * /
2520
+ * / `getEngramCard`'s `x402Support` reports THIS flag, so a buyer can read the rail's state before
2521
+ * / paying rather than discovering it in a refusal.
2522
+ */
2523
+ setPaidMemoryReadEnabled: ActorMethod<[boolean], Result_1>;
2524
+ /**
2525
+ * / Open or close the paid-memory WRITE rail (RB4). Owner-only, like its read twin.
2526
+ * /
2527
+ * / Kept as a SEPARATE flag rather than widening `setPaidMemoryReadEnabled` into one switch: an
2528
+ * / owner selling read access has not thereby agreed to sell write access, and a single flag makes
2529
+ * / the larger permission ride in on the smaller one. Two flags is the shape that lets an owner
2530
+ * / say yes to one and no to the other, which is the common case.
2531
+ */
2532
+ setPaidMemoryWriteEnabled: ActorMethod<[boolean], Result_1>;
2533
+ /**
2534
+ * / ⟨0.16.0, L1⟩ Every validation refusal here is `#Invalid` and the cap is `#Conflict`, and the
2535
+ * / split is worth stating once for the whole whole-value-config family below: a malformed path is
2536
+ * / the CALLER'S to fix and retrying with a corrected list works, while "max 20" is a property of
2537
+ * / this engram that no argument gets around. A caller that cannot tell those apart either edits
2538
+ * / forever or gives up on a request that was one character from valid.
2539
+ */
2540
+ setProtectedPaths: ActorMethod<[Array<string>], Result_1>;
2541
+ /**
2542
+ * / OWNER-ONLY: switch the metrics reader's read of the seat weeks off (`false`) or back on (`true`).
2543
+ * / On from birth, by the owner's ruling of 2026-10-02. Off, `sysGetAgentSeatWeeks` refuses the
2544
+ * / reader by name, naming this switch; the rows are still kept and the owner still reads them. Each
2545
+ * / call is a chained record entry (`metrics.setSeatWeeksReadEnabled`, the new and the old value), so
2546
+ * / when the read was on or off is part of the record. Anyone else is refused by name.
2547
+ */
2548
+ setSeatWeeksReadEnabled: ActorMethod<[boolean], Result_1>;
2549
+ /**
2550
+ * / Set the most this engram may spend per day ACROSS EVERY CALLER — five agents, the owner and the
2551
+ * / marketplace together. `null` removes the ceiling. ⟨2026-09-28⟩
2552
+ * / ⟨CORRECTED 2026-09-29, review finding X-8: "spend" was too wide. The ceiling covers the x402
2553
+ * / payments this engram signs (`signX402Payment` and the marketplace's `sysSignX402Payment`) and
2554
+ * / nothing else: it is the most this engram may sign in x402 payments per day. Two other signing
2555
+ * / paths are NOT counted against it — typed-data signatures (`signEip712` / `sysSignEip712`),
2556
+ * / bounded instead by each registered type's daily count and destination list; and agent-
2557
+ * / registration transactions (`signEngramRegistration`), bounded by three per caller per day and
2558
+ * / the 500-gwei gas ceiling. Whether the ceiling should cover them is a separate owner question.⟩
2559
+ * /
2560
+ * / WHY: the owner decided on 2026-09-28 to add one daily spending ceiling across all callers on an
2561
+ * / engram and keep the limit of five agents. Every other spending limit is per caller, so without
2562
+ * / this the engram's daily exposure was the SUM of up to seven allowances ($35.00 at the defaults)
2563
+ * / and nobody could see it. The amount is in the same minor units the per-caller caps compare
2564
+ * / (USDC's six decimals: 5_000_000 = $5.00), and like them it does not distinguish tokens.
2565
+ * /
2566
+ * / A payment that would take today's engram-wide total past this number is not signed: the caller
2567
+ * / gives a reason and it becomes a row in the approval queue, exactly as over a per-caller cap.
2568
+ * / `0` is allowed and means every payment needs the owner's approval.
2569
+ * / ⟨CORRECTED 2026-09-29, review finding X-2: not every payment — a payment of amount 0 crosses no
2570
+ * / limit, so it is signed under a ceiling of 0 too. Whether amount-0 payments should be refused is
2571
+ * / an open owner question.⟩ ⟨CORRECTED 2026-09-29, later — the owner ruled (follow-up 15, option A):
2572
+ * / a payment of amount 0 is now refused by name before any limit is read (`X402Input.refusal`), so
2573
+ * / under a ceiling of 0 every payment that can be signed at all does need the owner's approval.
2574
+ * / And a new engram no longer starts with no ceiling: it starts at `SpendCeiling.DEFAULT_ENGRAM_DAY`
2575
+ * / ($10.00 a day; follow-up 9, option A).⟩ Takes effect on the next
2576
+ * / payment, counted against what was ALREADY spent today (the total is kept whether or not a
2577
+ * / ceiling is set), so setting a ceiling at noon does not grant a fresh day.
2578
+ * /
2579
+ * / Unlike `setSpendPolicy`, this does NOT auto-approve pending requests it now covers — a request
2580
+ * / held by the ceiling waits for `approveRequest`, or the caller retries against the new ceiling.
2581
+ * / The auto-approval exists for per-caller raises and is kept away from the ceiling on purpose
2582
+ * / (see `resolvePendingOnPolicyRaise`).
2583
+ * /
2584
+ * / The record entry `spend.setCeiling` carries the new AND the previous value, so a widening is
2585
+ * / distinguishable from a tightening afterwards — the reason `spend.setPolicy` records its limits.
2586
+ * / Not blocked by a payments freeze, like `setSpendPolicy`: setting a limit moves no money.
2587
+ */
2588
+ setSpendCeiling: ActorMethod<[[] | [bigint]], Result_1>;
2589
+ /**
2590
+ * / Set this engram's spending caps.
2591
+ * /
2592
+ * / The audit row records the LIMITS, not merely that a change happened, so a WIDENING is
2593
+ * / distinguishable from a tightening afterwards. A quiet policy raise is the shape most custody
2594
+ * / incidents take, and "policy changed" alone cannot tell an investigator which way it moved.
2595
+ * /
2596
+ * / Raising a cap RESOLVES pending approval requests it now covers — that is the second half of
2597
+ * / the escalation an agent starts when it hits a limit, and without it the queue is a place
2598
+ * / requests go to expire.
2599
+ */
2600
+ setSpendPolicy: ActorMethod<[SpendingPolicy], Result_1>;
2601
+ /**
2602
+ * / Owner-only: set YOUR OWN safety rails on the funding path — a per-top-up ckUSDC ceiling and a
2603
+ * / minimum gap between top-ups. Read them back with `getTopUpLimits`.
2604
+ * /
2605
+ * / ⚠ THESE ARE THE OWNER'S LIMITS, NOT THE PLATFORM'S. "Limits" reads like something imposed;
2606
+ * / nothing outside this engram sets them, and an owner may raise them at will. They exist so a
2607
+ * / compromised agent key or a runaway agent cannot drain a wallet in one call or in a fast loop,
2608
+ * / which is a bound on YOUR OWN blast radius rather than on what you are permitted to spend.
2609
+ * /
2610
+ * / The cooldown defaults to five minutes. `cooldownSeconds = 0` removes the gap entirely, which
2611
+ * / is a real choice and not an error.
2612
+ * / ⟨API-105, 2026-08-24 — v3 phase X3⟩ ONE RECORD, NOT TWO ADJACENT NATS. This took
2613
+ * / `(newMaxCkusdcE6s : Nat, cooldownSeconds : Nat)` — the documented swap class, and a live one:
2614
+ * / the suite calls `setTopUpLimits(10_000_000n, 300n)`, and a caller who transposes those gets a
2615
+ * / 300-e6 cap with a 116-DAY cooldown. Candid matches positionally and both are `nat`, so the
2616
+ * / wire accepts it, the types accept it, and the engram is quietly unable to top itself up.
2617
+ * /
2618
+ * / The field names are NOT a new vocabulary — they are `getTopUpLimits`'s, which already answers
2619
+ * / `{ cooldownSeconds; maxCkusdcE6s }`. Setter and getter now share one shape, so read-modify-
2620
+ * / write is expressible and neither side can drift from the other without the compiler saying so.
2621
+ */
2622
+ setTopUpLimits: ActorMethod<[{ cooldownSeconds: bigint; maxCkusdcE6s: bigint }], Result_1>;
2623
+ /**
2624
+ * / Owner sets the World ID app_id + action + rp_id from their World Developer Portal (rp_id appears
2625
+ * / after "Enable World ID 4.0" on a production app). The action MUST be configured there with
2626
+ * / max_verifications = Unlimited (idempotent /verify → survives IC consensus). After setting this,
2627
+ * / register getWorldIdRpSignerAddress() as the rp_id's signer address in the Portal.
2628
+ */
2629
+ setWorldIdConfig: ActorMethod<[string, string, string], Result_1>;
2630
+ /**
2631
+ * / Submit a verified-human proof: the IDKitResult from the frontend's World ID flow, forwarded
2632
+ * / VERBATIM (compact JSON, as JSON.stringify emits) to World's /api/v4/verify/{rp_id} over an HTTPS
2633
+ * / outcall (never trust the client). The v4 endpoint verifies both 4.0 proofs and legacy 3.0 proofs,
2634
+ * / so the OrbLegacy migration path and the 4.0 endgame ride the same method. Owner-only. `nullifier`
2635
+ * / is the claimed unique-human pseudonym; it must appear verbatim inside resultJson, binding what we
2636
+ * / store to the payload the verifier actually accepted. Only proof_of_human credentials are accepted
2637
+ * / (selfie is farmable, passport/mnc are document identity — a different tier). Sets worldIdVerified
2638
+ * / and stores the result ONLY on a real verification success — never self-asserted.
2639
+ */
2640
+ setWorldIdProof: ActorMethod<[string, string], Result_1>;
2641
+ /**
2642
+ * / Sign a registered type. ONE call, owner-only, freeze-gated — the delay lives on registration
2643
+ * / (D2), never here: an emergency withdrawal must not need two owner round-trips.
2644
+ * /
2645
+ * / ⟨0.16.0⟩ PERSISTS beside the market's `sysSignEip712` (census row 177, ruled). The owner does
2646
+ * / not lose the ability to sign because a marketplace gained it, and the two share every control
2647
+ * / below the caller gate.
2648
+ */
2649
+ signEip712: ActorMethod<[Uint8Array | number[], Array<[string, Eip712Value]>], Result_4>;
2650
+ /**
2651
+ * / Sign the engram's own ERC-8004 registration tx for client-side broadcast: the engram signs, the client
2652
+ * / broadcasts and keeps the resulting registration id.
2653
+ * /
2654
+ * / Agent-accessible. The comment here claimed "saves ~55-85M cycles vs registerAgent" until
2655
+ * / 2026-08-17; `registerAgent` — the engram method that broadcast the registration itself — left
2656
+ * / the candid surface in commit d25b53b, so the comparison had outlived its other term. The
2657
+ * / saving was real and is now simply the shape of this method: no RPC outcall, no receipt poll.
2658
+ * / ⟨API-105, 2026-08-24 — v3 phase X3⟩ ONE REQUEST RECORD, not three adjacent nats.
2659
+ * /
2660
+ * / ⟨Ruling R-B3⟩ This method KEEPS. Census row 309 dispositions it `die` ("test-only; folds into
2661
+ * / signEip712 + registered type") and row 311 records the owner's answer: RULED 2026-08-20 —
2662
+ * / KEEP, ERC-8004 stays. Both halves of the `die` rationale fail at the site: it is not
2663
+ * / test-only (a downstream web client's billing page calls it), and it is not a shipped customer
2664
+ * / capability either — that panel sits behind `evmBilling: { mode: 'off' }` in both the flag
2665
+ * / defaults and the shipped config, and its own dialog says the signature is dormant and not
2666
+ * / broadcastable. It is a real surface in a disabled state, which is neither thing the census
2667
+ * / row claimed.
2668
+ * /
2669
+ * / THE SWAP CLASS, and here it is three-deep: `nonce`, `maxFeePerGas` and `maxPriorityFeePerGas`
2670
+ * / were adjacent and all `Nat`. Transposing the two gas fields type-checks, decodes, and signs a
2671
+ * / transaction whose priority fee exceeds its max fee — invalid on chain, and the 500-gwei
2672
+ * / ceiling below cannot see it because both values are individually under the cap. Named fields
2673
+ * / remove the class.
2674
+ * /
2675
+ * / ⟨2026-09-28⟩ LIMITED PER CALLER PER DAY. The owner decided to cap this signature rather than
2676
+ * / delete it: each caller (the owner, or an active agent) may obtain
2677
+ * / `EngramRegCap.MAX_PER_CALLER_PER_DAY` registration signatures per UTC day; the next is refused
2678
+ * / with `#Conflict` naming this method. A signature that fails does not count. The `nonce` must
2679
+ * / be the REGISTRATION address's nonce — `getEvmAddress().engramRegistration` — below 2^64 − 1.
2680
+ */
2681
+ signEngramRegistration: ActorMethod<
2682
+ [
2683
+ {
2684
+ maxFeePerGas: bigint;
2685
+ nonce: bigint;
2686
+ maxPriorityFeePerGas: bigint;
2687
+ },
2688
+ ],
2689
+ Result_9
2690
+ >;
2691
+ /**
2692
+ * / Sign an EIP-3009 authorization for x402 payment. Agent-accessible.
2693
+ * / Client probes the URL, extracts chain/token/recipient/amount from the 402, and calls this.
2694
+ * / Canister signs → returns header → client retries with header.
2695
+ * /
2696
+ * / ⟨0.16.0⟩ PERSISTS beside the market's `sysSignX402Payment` (census row 177, ruled). An agent
2697
+ * / with an x402 rail does not lose it because a marketplace gained one, and both run the same body.
2698
+ * / ⟨API-105, 2026-08-24 — v3 phase X3⟩ ONE REQUEST RECORD, not eight positional arguments.
2699
+ * /
2700
+ * / THE HAZARD IS FUNDS MISDIRECTION, and it is the sharpest case in this batch. `tokenAddress`
2701
+ * / and `recipient` were ADJACENT and both `Text`. Candid matches positionally, so transposing
2702
+ * / them type-checks, decodes, and signs a payment whose payee is the TOKEN CONTRACT rather than
2703
+ * / the intended one — an irreversible outbound signature spending the engram's own key, with
2704
+ * / nothing between the mistake and the money. `tokenName`/`tokenVersion` are a second adjacent
2705
+ * / Text pair; that one only corrupts the EIP-712 domain, so it fails loudly instead.
2706
+ * /
2707
+ * / Named fields remove the class outright: a transposition is now a decode error at the edge.
2708
+ * /
2709
+ * / The body is UNCHANGED. Each parameter was referenced exactly once below, so the record is
2710
+ * / destructured on entry rather than threaded through — the diff is the signature and this line,
2711
+ * / which is what makes a reshape of a money path reviewable.
2712
+ */
2713
+ signX402Payment: ActorMethod<
2714
+ [
2715
+ {
2716
+ tokenVersion: string;
2717
+ tokenAddress: string;
2718
+ approvalId: [] | [string];
2719
+ recipient: string;
2720
+ rationale: [] | [string];
2721
+ tokenName: string;
2722
+ chainId: bigint;
2723
+ amount: bigint;
2724
+ },
2725
+ ],
2726
+ Result_3
2727
+ >;
2728
+ /**
2729
+ * / Self-heal: if the registry's spawn-time push was missed, the owner pulls the number from
2730
+ * / the spawning registry. Idempotent; fails closed if the registry has no record.
2731
+ */
2732
+ syncEngramNumber: ActorMethod<[], Result_8>;
2733
+ /**
2734
+ * / Genesis seed — the atomic "spawn only when there's real content" primitive. The spawning
2735
+ * / REGISTRY pushes the owner's first real memory immediately after install, so a canister is
2736
+ * / never spawned holding nothing (see the registry's `provisionEngram` optional genesis).
2737
+ * /
2738
+ * / Gated `spawnedBy`-only and ONE-SHOT: it refuses once any file exists, so it can seed and never
2739
+ * / overwrite. Unlike the owner-only `seedMemory` placeholder this is REAL owner content, so it
2740
+ * / IS counted as an owner write (`firstWriteAt`, `totalMemoryWrites`) and is authored by the
2741
+ * / OWNER rather than by the registry principal that called it. It never touches the
2742
+ * / agent metrics.
2743
+ * /
2744
+ * / ⚠ THE PAYLOAD IS `Nat` AND MUST STAY `Nat`, which is a constraint on any client of this
2745
+ * / method rather than an internal detail. Its only caller is the registry, over an
2746
+ * / inter-canister boundary, through a hand-declared actor type — and the registry is ROUTINELY a
2747
+ * / different version from the engram template it is seeding: it upgrades before the fleet does,
2748
+ * / and during a transition it can serve a template older than itself. A return-type change here
2749
+ * / breaks genesis provisioning across that skew. That is measured, not predicted: the registry
2750
+ * / trapped with "IDL error: unexpected IDL type when parsing Nat" while seeding an engram built
2751
+ * / at the staging tag. A receipt would buy nothing anyway — the caller does `ignore await`.
2752
+ * /
2753
+ * / ⚠ ORDERING: upload the engram TEMPLATE first, then upgrade the registry. The reverse leaves a
2754
+ * / window where a spawn seeds an old-shape engram with a new-shape expectation; the reply fails
2755
+ * / to decode and `provisionEngram` dies on a trap its own `try/catch` cannot reach (ADR-0001),
2756
+ * / failing the WHOLE SPAWN rather than just the seed.
2757
+ */
2758
+ sysApplyGenesisSeed: ActorMethod<[string, Uint8Array | number[]], Result_8>;
2759
+ /**
2760
+ * / OWNER force-close, for a session the payer abandoned.
2761
+ * /
2762
+ * / ⟨R1b, ruled 2026-08-26: owner-gated, NO guardian.⟩ It moves someone else's money, and only ever
2763
+ * / BACK TO THEM — the destination is the session's own payer and is not caller-influenced, so the
2764
+ * / guardian ceremony that guards destination changes buys nothing here and would strand payers on
2765
+ * / engrams that have no guardian.
2766
+ * /
2767
+ * / Calls the gateway's NO-AUTH variant deliberately. `gate.closeSession` is payer-only, which is
2768
+ * / why the market's admin-gated `forceCloseSession` could never work: it authorised an admin and
2769
+ * / then delegated to a method that rejects everyone but the payer.
2770
+ * /
2771
+ * / ⟨NOTE 2026-10-02 — NOT RENAMED, deliberately, and this is the one `sys` method that still has a
2772
+ * / human caller.⟩ The sys-tier retier (ruled 2026-08-24, executed 2026-10-02 on the registry and
2773
+ * / the market) named FOUR admin-called methods; this one became owner-gated two days after that
2774
+ * / list was made, so the ruling never named it. Its caller is the OWNER, a person, which is the
2775
+ * / exact thing the retier removes from the `sys` tier — so "a `sys` method has no human caller"
2776
+ * / stays false here until it is renamed too. Left for the owner: the rename is free until the cut
2777
+ * / and a break after it, and it also moves `packages/client/README.md` and
2778
+ * / `docs/AGENT-ONBOARDING.md`, which name it.
2779
+ */
2780
+ sysForceCloseSession: ActorMethod<[string], Result_1>;
2781
+ /**
2782
+ * / The metrics reader the registry designated reads every engagement's seat weeks, in one call.
2783
+ * /
2784
+ * / CALLER: the metrics reader the spawning registry named on this engram (`metricsReaderId`), and
2785
+ * / nobody else — not the owner (who reads `getAgentSeatWeeks`), an agent, a guardian, the registry,
2786
+ * / the biller or the market (ADR-0020: a `sys` method names its caller). Answered only while the
2787
+ * / owner leaves it on (`seatWeeksReadEnabled`, on from birth by the owner's ruling of 2026-10-02).
2788
+ * /
2789
+ * / WHAT LEAVES: per engagement, the pairing day, the first and last payment-signature days, the
2790
+ * / 64-week map and the count — NO root, NO invite, NO amount, recipient or nonce. The reader matches
2791
+ * / rows to the registry's engagements by day, so no agent's identity leaves this engram here.
2792
+ * /
2793
+ * / ⟨L7⟩ UPDATE, NOT QUERY, so a refusal leaves its `sysGetAgentSeatWeeks.denied` row naming the
2794
+ * / caller's class, and an answered read leaves a `sysGetAgentSeatWeeks` row in the read log — the
2795
+ * / owner can see every time the reader read. A refusal is `#Refused` naming this method and the
2796
+ * / class (`SeatWeeks.readRefusal`), never an empty list: an empty list is a real answer ("no agent
2797
+ * / has paired here"), and a fabricated one would be counted as one.
2798
+ */
2799
+ sysGetAgentSeatWeeks: ActorMethod<[], Result_7>;
2800
+ /**
2801
+ * / The metrics reader the registry designated reads this engram's paid-rail health, in one call:
2802
+ * / the balance and the line it must stay above, the memory that line is computed from, the sessions
2803
+ * / by state, the escrow open sessions hold, the vouchers spent and the refused ones
2804
+ * / (`RailHealth.RailHealth` says what each is, and what is never in it).
2805
+ * /
2806
+ * / CALLER: the metrics reader the spawning registry named on this engram (`metricsReaderId`), and
2807
+ * / nobody else — the owner reads its balance through `getOwnerConsole`. Answered only while the
2808
+ * / owner leaves that reader's read on (`seatWeeksReadEnabled`): the SAME gate and the SAME switch
2809
+ * / as `sysGetAgentSeatWeeks`, because it is the same reader and the owner has one switch over it.
2810
+ * /
2811
+ * / A QUERY, AND A DEPARTURE FROM THE SYS METHODS BESIDE IT, ON PURPOSE ⟨2026-10-02⟩. It is read
2812
+ * / every hour, and as an update it would leave a row in this engram's read log every hour — about
2813
+ * / 720 a month in a record whose rows are what its owner reads. What a query cannot do is write the
2814
+ * / denial row of a refusal (a query's writes are discarded) — the trade `getOwnerConsole` makes. A
2815
+ * / refusal is still `#Err(#Refused …)` naming this method and the caller's class
2816
+ * / (`RailHealth.readRefusal`), never a zero balance: a made-up zero would read as an engram about
2817
+ * / to freeze. Called by another canister, a query runs replicated and this engram pays for it —
2818
+ * / a few million cycles an hour, the cost of being watched.
2819
+ */
2820
+ sysGetRailHealth: ActorMethod<[], Result_6>;
2821
+ /**
2822
+ * / The cashier reads how many signatures this engram has produced, per caller and in total.
2823
+ * / ⟨2026-09-28⟩ The owner's decision of that date: a running counter on the engram, exported to
2824
+ * / the cashier — and to nobody else (`AccessControl.requireCashierForSignatureCounts`).
2825
+ * /
2826
+ * / ONE NEW METHOD ON THE ENGRAM, not a field on the registry's `sysMeterEngram` reply. The study
2827
+ * / ruled out widening that reply to protect deployed clients, and that reason is gone (nothing is
2828
+ * / launched; the next release reinstalls every canister). The deciding fact is a different one,
2829
+ * / read at the site: `sysMeterEngram` is the REGISTRY's method and answers from the management
2830
+ * / canister's `canister_status` — the registry holds no signature count. Carrying the count in its
2831
+ * / reply would add a registry-to-engram call inside the meter and a second trust hop between the
2832
+ * / counter and the biller. The cashier is already the engram's recognised biller (`cashierId`) and
2833
+ * / already calls it directly (`sysRecordFeeEvent`), so it reads the count at the source.
2834
+ * /
2835
+ * / UPDATE, NOT QUERY, so that a refusal leaves its `sysGetSignatureCounts.denied` row: a refused
2836
+ * / query cannot write one (see `Gated.mo`'s header). A refusal is `#Refused` naming this method,
2837
+ * / never an empty list or a zero — a zero is a real answer, and a fabricated one would be billed.
2838
+ * /
2839
+ * / ⟨2026-09-29⟩ Each row names the key, the agent it was enrolled under (none for the owner and
2840
+ * / the marketplace) and the role, so one agent's keys can be added up. And a limit for whoever
2841
+ * / bills from this: the number comes from a canister its owner controls and can reinstall, so bill
2842
+ * / only engrams the registry confirms run published code, and read a lower count than last time as
2843
+ * / a reinstall — the reasoning is at `signaturesByCaller`.
2844
+ */
2845
+ sysGetSignatureCounts: ActorMethod<[], Result_5>;
2846
+ /**
2847
+ * / Rent lifecycle notice — how the OWNER (not the agent) learns their subscription lapsed. D6
2848
+ * / shipped the handoff but every alarm it added talks to the operating service's watchdog; the
2849
+ * / doc named the debt plainly: "an owner learns of their own lapse only by looking." This closes
2850
+ * / it through the channel the owner already has: the entry lands in the audit log under `rent.*`,
2851
+ * / ActionAlerts classifies that as #money (default ON), and the drain delivers it to the owner's
2852
+ * / webhook. No new channel, no new config — an owner who armed alerts gets told.
2853
+ * /
2854
+ * / Gated exactly like sysRecordFeeEvent (spawnedBy or cashierId): the sweep is the only thing that
2855
+ * / OBSERVES the transition, so it is the only thing that can report it. The state whitelist is
2856
+ * / closed — this is a lifecycle feed, not a free-text push surface into the owner's audit chain.
2857
+ */
2858
+ sysNotifyRentLifecycle: ActorMethod<[string, string], Result_1>;
2859
+ /**
2860
+ * / ⟨0.16.0⟩ `getWalletActivation()` DELETED — folded to `about().walletActivatedAtNs`, with its
2861
+ * / custody-posture rationale carried onto the field. "Can this thing hold money" is a question a
2862
+ * / counterparty is entitled to ask before dealing with an engram, which is why it stays public.
2863
+ * / ⟨0.16.0, sys tier⟩ THE MARKET TELLING CUSTODY, which is the half of the wallet-activation
2864
+ * / story the engram cannot see for itself.
2865
+ * /
2866
+ * / B1 moved the storefront to the market, so listing an endpoint — a seller offering to be paid —
2867
+ * / happens on a canister this one does not observe. `walletActivatedAt` exists to raise a custody
2868
+ * / decision (a wallet-bearing engram is sovereign-by-default and its owner has a claimSovereignty
2869
+ * / still to complete), and a seller who has never derived an EVM address would have gone
2870
+ * / unstamped forever. That is the under-reporting direction, which is the harmful one: a missing
2871
+ * / flag retires a decision that is still pending.
2872
+ * /
2873
+ * / ONE METHOD, NOT A FAMILY (L6). The other surface the old comment named — opening a payment
2874
+ * / session — is NOT here and is not an omission: measured at the market 2026-08-20, `openSession`'s
2875
+ * / caller is a BUYER, and a buying engram signs with a key it derived through `getEvmAddress`,
2876
+ * / which stamps. It is already marked before it can pay. Adding a case for it would be surface
2877
+ * / bought for a gap that does not exist.
2878
+ * /
2879
+ * / THE SURFACE WHITELIST IS CLOSED, exactly as `sysNotifyRentLifecycle`'s state whitelist is, and
2880
+ * / for the same reason: this is a lifecycle feed, not a free-text push into the owner's audit
2881
+ * / chain. The market is trusted to REPORT, never to compose what the owner reads.
2882
+ * /
2883
+ * / IDEMPOTENT AND SILENT WHEN ALREADY STAMPED. `markWalletActivated` returns early once the var is
2884
+ * / set, so a second notice writes nothing and still answers `#Ok` — a retry learns it succeeded
2885
+ * / rather than that it failed. The stamp keeps the FIRST wallet-bearing moment, which is the one a
2886
+ * / custody audit wants; a later notice must not overwrite it with its own time.
2887
+ * /
2888
+ * / The audit line records this engram as the subject, and `surface=endpoint-listed` is what names
2889
+ * / the origin: only the configured market can pass that value, so the line cannot be produced by
2890
+ * / any other caller.
2891
+ */
2892
+ sysNotifyWalletActivity: ActorMethod<[string], Result_1>;
2893
+ /**
2894
+ * / The rent RECEIPT seam (B2): the cashier tells this engram that money moved on its behalf, and
2895
+ * / the engram appends a `fee.recorded` line to its own audit chain. It computes nothing.
2896
+ * /
2897
+ * / ⚠ GATED TO TWO PRINCIPALS AND NEITHER IS THE OWNER — the SPAWNING REGISTRY or the CONFIGURED
2898
+ * / CASHIER. An owner cannot write their own fee receipts, which is the point: a receipt an owner
2899
+ * / could forge is not evidence. `getBillerId` publishes which cashier this engram accepts, so the
2900
+ * / same fact is checkable from outside.
2901
+ * /
2902
+ * / This is the whole of what B2 left on the engram. Entitlement, custody and fee math live on the
2903
+ * / cashier; here there is an append-only record and no arithmetic — so a disagreement between the
2904
+ * / two is visible rather than reconciled silently.
2905
+ * / ⟨API-105/ARCH-108, 2026-08-24 — v3 phase X3⟩ ONE FEE-EVENT RECORD, not three positional
2906
+ * / arguments. ARCH-108 records that the census prescribed this fold and it "was refused for a
2907
+ * / wire-break reason the ruling voids", with the instruction to execute it or ratify
2908
+ * / positional-forever with a dated note — "silence spends the window". Executed.
2909
+ * /
2910
+ * / The argument for a record here is EVOLUTION, not transposition: unlike `setTopUpLimits`'s two
2911
+ * / adjacent nats, these three types differ, so a swap would not type-check. What positional
2912
+ * / arguments cost is the next field. A fee event is exactly the shape that grows one — token,
2913
+ * / amount, rate — and ADR-0018's rule is that an INBOUND record gains optional fields forever
2914
+ * / while an argument LIST cannot gain anything without breaking every caller at once.
2915
+ * /
2916
+ * / ⚠ ALL FOUR CALLERS MOVE IN THE SAME CHANGE, and this is ADR-0001's fatal direction: three
2917
+ * / inline hand-IDLs in the cashier and one in the registry declare this method's argument shape
2918
+ * / structurally. Every one of them sits inside `try { … } catch (_e) {}`, which reads as
2919
+ * / containment and is not: a reply-decode mismatch calls `ic0.trap` INSIDE the caller's own
2920
+ * / callback, and Motoko's `catch` sees rejects, never traps. That is the failure that took
2921
+ * / production monitoring dark for ~33h. The ENGRAM WASM MUST SHIP BEFORE its callers, and
2922
+ * / `check-didc-compat` is suspended for the cut, so nothing mechanical will catch a wrong order.
2923
+ */
2924
+ sysRecordFeeEvent: ActorMethod<
2925
+ [
2926
+ {
2927
+ paidThroughNs: [] | [bigint];
2928
+ cycles: bigint;
2929
+ scheduleVersion: [] | [string];
2930
+ },
2931
+ ],
2932
+ Result_1
2933
+ >;
2934
+ /**
2935
+ * / Point this engram at the biller that converts its tokens → cycles. Settable, not hardcoded:
2936
+ * / coupling is by principal id, so the same wasm runs against any deployment's biller.
2937
+ * /
2938
+ * / ⟨0.16.0, B2⟩ Renamed from `setCashierId`, and NARROWED to the spawning registry (census row
2939
+ * / 266, ruled). Two changes, for two reasons:
2940
+ * / · "cashier" is a PLATFORM word and this is the OSS wire. `biller` names the role, not the
2941
+ * / product that fills it.
2942
+ * / · The write is now sys-tier. It previously accepted the OWNER as well, and that second
2943
+ * / writer is what the ruling removed — three writers for one field (owner, spawner, and the
2944
+ * / frontend acting for the owner) is a last-write-wins race over a money-routing target.
2945
+ * /
2946
+ * / ⚠ THE COST, RULED AND ACCEPTED: an engram whose registry never set this has NO owner remedy.
2947
+ * / `convertEarningsToCycles` fails closed against a null biller, and with the owner leg gone
2948
+ * / nobody but the spawning registry can fix it. That refusal therefore names the real remedy
2949
+ * / rather than telling an owner to run a call they can no longer make.
2950
+ */
2951
+ sysSetBillerId: ActorMethod<[Principal], Result_1>;
2952
+ /**
2953
+ * / One-shot assignment of the spawn ordinal — callable ONLY by the spawning registry, ONLY
2954
+ * / while unset. Neither the owner nor any later registry can change an assigned number.
2955
+ */
2956
+ sysSetEngramNumber: ActorMethod<[bigint], Result_1>;
2957
+ /**
2958
+ * / Point this engram at the commerce satellite allowed to ask it for signatures. ⟨0.16.0, B1⟩
2959
+ * /
2960
+ * / SAME AUTHORITY AS `sysSetBillerId`, and for a stronger reason. That one routes money; this one
2961
+ * / confers the capability to ask this canister to sign with its own tECDSA key. Three writers for
2962
+ * / one field would be a last-write-wins race over a SIGNING target — so the spawning registry is
2963
+ * / the only writer, and an engram with no registry has no market to be pointed at.
2964
+ * /
2965
+ * / The same accepted cost applies, one notch sharper: an engram whose registry never set this can
2966
+ * / never be sold through the market, and no owner action fixes it. Both `sysSign*` methods refuse
2967
+ * / against a null pointer and their refusals name the registry as the remedy rather than telling
2968
+ * / an owner to run a call they cannot make.
2969
+ */
2970
+ sysSetMarketId: ActorMethod<[Principal], Result_1>;
2971
+ /**
2972
+ * / Name the metrics reader allowed to read this engram's seat weeks (`sysGetAgentSeatWeeks`).
2973
+ * / ⟨2026-10-02, the owner's ruling of that day⟩
2974
+ * /
2975
+ * / CALLER: the registry that spawned this engram, and nobody else (ADR-0020) — the same authority
2976
+ * / as `sysSetBillerId` and `sysSetMarketId`. The registry calls it once, at spawn, last of its
2977
+ * / pushes, with exactly this interface: `sysSetMetricsReaderId : (Principal) -> async
2978
+ * / Wire.Result<()>`. ⚠ THAT CLIENT DECLARATION IS HAND-WRITTEN AT THE REGISTRY: a different NAME
2979
+ * / here leaves every newborn with no reader, silently (the push is best-effort and its reject is
2980
+ * / caught), and a different REPLY type traps inside the registry's callback. Rename neither without
2981
+ * / the registry; test/seat-weeks-wiring.test.ts compares the two.
2982
+ * /
2983
+ * / A CANISTER ONLY: a person's principal, the anonymous principal or the management canister is
2984
+ * / refused `#Invalid` and nothing changes — a person named here would be handed this engram's seat
2985
+ * / counts. Set or replaced, never cleared: the owner's control is the switch
2986
+ * / (`setSeatWeeksReadEnabled`), not the pointer. The chained record entry
2987
+ * / (`metrics.sysSetMetricsReaderId`) is the evidence of when the read was granted, and to whom.
2988
+ */
2989
+ sysSetMetricsReaderId: ActorMethod<[Principal], Result_1>;
2990
+ /**
2991
+ * / The market asks this engram to sign a registered type — B1's seam, settlement leg. ⟨0.16.0⟩
2992
+ * /
2993
+ * / THE ENGRAM DOES NOT TRUST THE MARKET WITH ANYTHING BEYOND "ask". Every control that bounds
2994
+ * / what may be signed stays here and is unchanged: the type must already be OWNER-REGISTERED
2995
+ * / (the market cannot introduce a shape), its cool-off must have elapsed, its per-type daily cap
2996
+ * / still binds, the destination allowlist still fails closed, and a payments freeze still stops
2997
+ * / it. What the market supplies is the request; what the engram supplies is the whole policy.
2998
+ * /
2999
+ * / That is what "signatures only" means in code, and it is why this method needs no new authority
3000
+ * / model: an unregistered typeId is refused for the market exactly as it is for the owner.
3001
+ */
3002
+ sysSignEip712: ActorMethod<[Uint8Array | number[], Array<[string, Eip712Value]>], Result_4>;
3003
+ /**
3004
+ * / The market asks this engram to sign an x402 payment — B1's seam, the paid-request leg. ⟨0.16.0⟩
3005
+ * /
3006
+ * / THE MARKET SUPPLIES THE REQUEST; THE ENGRAM SUPPLIES THE POLICY. Every control below the caller
3007
+ * / gate is unchanged and still binds: a payments freeze stops it, the recipient must be on the
3008
+ * / owner's EVM allowlist if the owner has set one, the per-transaction and per-day caps hold, and
3009
+ * / an over-policy request goes to the OWNER'S approval queue rather than through.
3010
+ * /
3011
+ * / `#ApprovalPending` is a real answer here, not an error, exactly as it is for an agent: the
3012
+ * / market is told the spend needs the owner and can retry with the `approvalId` once granted. A
3013
+ * / caller that treats it as a failure will simply never complete a spend the owner would have
3014
+ * / allowed — which is the safe direction, and the reason it rides inside `Ok` (L5).
3015
+ * /
3016
+ * / READ `x402SignFor`'s declaration before setting a policy for this caller. The cap is ONE bucket
3017
+ * / for ALL market traffic; per-seller limits are not expressible in the store it reads.
3018
+ */
3019
+ sysSignX402Payment: ActorMethod<
3020
+ [bigint, string, string, bigint, string, string, [] | [string], [] | [string]],
3021
+ Result_3
3022
+ >;
3023
+ /**
3024
+ * / Write an `alerts.test` entry into the audit log; the drain timer delivers it to the webhook
3025
+ * / within ~60s. Owner-only; requires a configured URL so the test can actually go somewhere.
3026
+ */
3027
+ testActionAlert: ActorMethod<[], Result_1>;
3028
+ /**
3029
+ * / Guardian test alert — an audited guardian action (`alerts.test`, role Guardian) that every
3030
+ * / armed channel (owner + guardians) receives within ~60s. Requires the caller's own channel
3031
+ * / to be armed so the test has somewhere to land for them.
3032
+ */
3033
+ testGuardianAlert: ActorMethod<[], Result_1>;
3034
+ /**
3035
+ * / RENAMED from `init` (L2.4). This is the OWNERSHIP-TRANSFER method — the most consequential
3036
+ * / owner-facing operation on the canister — and it was named for first-time setup, colliding with
3037
+ * / the actor's own `service : (initArgs)`. A reader scanning for "how does ownership move" found
3038
+ * / nothing; a reader scanning for `init` found a constructor.
3039
+ * /
3040
+ * / Its read counterpart is `listOwnershipTransfers` (was `getOwnershipHistory`), which now shares
3041
+ * / the stem — the pair was previously unfindable from either half.
3042
+ * / ⟨0.16.0, L1⟩ TWO OF THESE REFUSALS ARE THE FIRST-CLAIM PATH, and they are not authorization.
3043
+ * /
3044
+ * / On an unowned engram there is no owner to refuse anyone, so "caller must set themselves as
3045
+ * / owner" is a rule about the ARGUMENT — pass your own principal and it succeeds. `#Invalid` says
3046
+ * / retrying with a different argument can work; `#Refused` would tell a first claimant their
3047
+ * / standing was the problem, on the one call where nobody has standing yet.
3048
+ * /
3049
+ * / ⟨2026-09-29, owner ruling follow-up 8 (option A)⟩ A CHANGE OF OWNER HANDS OVER CONTROL OF THE
3050
+ * / CODE. The new owner becomes a controller of this canister and the former owner stops being one;
3051
+ * / the answer says who moved it (`ControlHandover`). Managed: the registry moves it while it
3052
+ * / accepts the transfer. Sovereign: the registry answers `#EngramMustMove` and this engram sets
3053
+ * / its own controllers. THE OWNER CHANGES HERE ONLY AFTER CONTROL HAS MOVED — if it cannot move,
3054
+ * / the registry's record is put back and nothing is transferred; if even that fails, the refusal
3055
+ * / says who the registry now records and that the same call again finishes it. A standalone
3056
+ * / engram (no registry) cannot know who controls it and changes the owner only, answering
3057
+ * / `#NotHeldHere`. The rules are `src/shared/ControlHandover.mo`'s.
3058
+ * /
3059
+ * / ⟨2026-09-29, review PR-3: a half-finished change of owner⟩ The registry now MARKS a change of
3060
+ * / owner as unfinished from the moment it moves its record until it sees control move. A sovereign
3061
+ * / engram therefore reports the move (`sysConfirmOwnershipTransfer`) after setting its own
3062
+ * / controllers; until the registry hears it, the registry refuses the new owner's
3063
+ * / `claimSovereignty`, `returnToManaged`, `abandonMyEngram` and `upgradeMyEngram` for this engram.
3064
+ * / While a transfer is marked unfinished, a transfer to anyone but its would-be owner is refused by
3065
+ * / the registry, by name; calling this again with that owner finishes it.
3066
+ * /
3067
+ * / ⟨2026-09-29, review finding RV-4⟩ THE OWNER NAMING THEMSELVES IS A REPORT, NOT A HAND-ON. It is
3068
+ * / the way out when the registry did not hear that a sovereign engram moved control: it moves
3069
+ * / control to the same owner again and reports it, and it writes NO entry to
3070
+ * / `listOwnershipTransfers` (until this day it wrote one from the owner to themselves, a hand-on
3071
+ * / that did not happen). The record entry says it was a report. `ControlHandover.isReport`.
3072
+ */
3073
+ transferOwnership: ActorMethod<[Principal], Result_2>;
3074
+ /**
3075
+ * / OWNER-ONLY release of the payment freeze — and the asymmetry with `freezePayments` is the
3076
+ * / governance design, not an oversight.
3077
+ * /
3078
+ * / ⚠ A GUARDIAN CAN PULL THIS BRAKE AND CANNOT RELEASE IT. `freezePayments` accepts the owner OR
3079
+ * / a guardian holding `canFreezePayments`; only the owner reaches this method. Two consequences,
3080
+ * / and both parties should know them before the role is accepted:
3081
+ * / · a guardian can stop payments in an emergency WITHOUT the owner, which is the point;
3082
+ * / · a guardian cannot hold the engram hostage, because the owner releases it immediately and
3083
+ * / unilaterally.
3084
+ * / So a guardian's freeze is a TRIPWIRE, not a lock — it buys the time it takes the owner to
3085
+ * / look, and no more.
3086
+ */
3087
+ unfreezePayments: ActorMethod<[], Result_1>;
3088
+ /**
3089
+ * / Consensus transform for the World ID /verify outcall. Replicas each call independently, so the raw
3090
+ * / response (timestamps, `uses`, request-id headers) is non-deterministic. Collapse it to a single
3091
+ * / canonical byte — "1" iff HTTP 200 AND the body asserts success — with no headers, so every replica
3092
+ * / agrees. The caller keys off this byte, never the raw body.
3093
+ * /
3094
+ * / PUBLIC: not a choice, exactly as `actionAlertTransform` above — the management canister calls
3095
+ * / it on every replica with no caller identity attached. Stateless and total, so being callable
3096
+ * / by anyone grants nothing: an outsider invoking it learns only what they already passed in.
3097
+ */
3098
+ worldIdTransform: ActorMethod<
3099
+ [{ context: Uint8Array | number[]; response: HttpRequestResult }],
3100
+ HttpRequestResult
3101
+ >;
3102
+ /**
3103
+ * / Write a memory file, creating it or adding a version to it. Returns a write receipt — the new
3104
+ * / `version`, the audit `seq`, and the chain `head` after the write — so a caller can prove what
3105
+ * / it wrote without a second read.
3106
+ * /
3107
+ * / ⚠ OWNER-ONLY, and this is the one most likely to surprise: an agent holding `write_memory`
3108
+ * / does NOT reach this method. Agent writes go through the agent surface, which applies the
3109
+ * / grant and the protected-path rules on top. `#Refused` here means the caller is not the owner,
3110
+ * / not that a permission is missing.
3111
+ * /
3112
+ * / It also refuses while writes are PAUSED and while memory is not attached — both are states an
3113
+ * / owner can be in without knowing, so they answer as themselves rather than as a generic failure.
3114
+ * /
3115
+ * / ⚠ THE FILE-COUNT CAP BLOCKS NEW FILES ONLY. At the cap, creating a new path is refused and
3116
+ * / APPENDING TO AN EXISTING FILE STILL WORKS — the refusal says so, because "you are full" and
3117
+ * / "you cannot write at all" lead to different next actions. A TOMBSTONED path counts as absent,
3118
+ * / so writing to a deleted path is a new file and is capped like one; the delete record survives
3119
+ * / either way.
3120
+ * /
3121
+ * / Path and content are validated before the caller is even checked, so a malformed request gets
3122
+ * / `#Invalid` rather than a refusal it would waste time investigating.
3123
+ */
3124
+ writeMemory: ActorMethod<[string, Uint8Array | number[]], Result>;
3125
+ }
3126
+ export interface EngramSessionState {
3127
+ id: string;
3128
+ status: EngramSessionStatus;
3129
+ deposited: bigint;
3130
+ openedAtNs: bigint;
3131
+ lastActivityAtNs: bigint;
3132
+ consumed: bigint;
3133
+ voucherCount: bigint;
3134
+ remaining: bigint;
3135
+ payer: Principal;
3136
+ }
3137
+ export type EngramSessionStatus =
3138
+ { closed: null } | { expired: null } | { other: string } | { open: null } | { closing: null };
3139
+ export interface Enrolment {
3140
+ signature: Uint8Array | number[];
3141
+ enrolledKey: Principal;
3142
+ rootPubkey: Uint8Array | number[];
3143
+ engram: Principal;
3144
+ }
3145
+ export interface EnrolmentProof {
3146
+ signature: Uint8Array | number[];
3147
+ enrolledKey: Principal;
3148
+ rootPubkey: Uint8Array | number[];
3149
+ inviteCode: string;
3150
+ }
3151
+ export type Error =
3152
+ | { Invalid: string }
3153
+ | { NotFound: string }
3154
+ | { Refused: string }
3155
+ | { Other: string }
3156
+ | { Unavailable: string }
3157
+ | { Conflict: string };
3158
+ export interface EvmAddresses {
3159
+ pay: string;
3160
+ engramRegistration: string;
3161
+ }
3162
+ export interface ExportReceiptRow {
3163
+ by: Principal;
3164
+ seq: bigint;
3165
+ toSeq: bigint;
3166
+ opsRoot: Uint8Array | number[];
3167
+ atNs: bigint;
3168
+ fromSeq: bigint;
3169
+ authorFilter: [] | [Principal];
3170
+ }
3171
+ export interface GenesisNote {
3172
+ predecessorSize: [] | [bigint];
3173
+ predecessorHeadHash: [] | [Uint8Array | number[]];
3174
+ note: string;
3175
+ version: string;
3176
+ genesisAtNs: bigint;
3177
+ }
3178
+ export interface GuardianPermissions {
3179
+ canFreezePayments: boolean;
3180
+ canRevokeAgents: boolean;
3181
+ scopes: [] | [Array<string>];
3182
+ canPauseWrites: boolean;
3183
+ }
3184
+ export interface GuardianRecord {
3185
+ status: GuardianStatus;
3186
+ permissions: GuardianPermissions;
3187
+ principal: Principal;
3188
+ name: string;
3189
+ addedAtNs: bigint;
3190
+ }
3191
+ export type GuardianStatus = { Active: null } | { Pending: null };
3192
+ export interface HeldKey {
3193
+ key: Principal;
3194
+ from: LogPosition;
3195
+ until: LogPosition;
3196
+ }
3197
+ export interface HttpHeader {
3198
+ value: string;
3199
+ name: string;
3200
+ }
3201
+ export interface HttpRequest {
3202
+ url: string;
3203
+ method: string;
3204
+ body: Uint8Array | number[];
3205
+ headers: Array<[string, string]>;
3206
+ }
3207
+ export interface HttpRequestResult {
3208
+ status: bigint;
3209
+ body: Uint8Array | number[];
3210
+ headers: Array<HttpHeader>;
3211
+ }
3212
+ export interface HttpResponse {
3213
+ body: Uint8Array | number[];
3214
+ headers: Array<[string, string]>;
3215
+ upgrade: [] | [boolean];
3216
+ status_code: number;
3217
+ }
3218
+ export interface KeyNomination {
3219
+ key: Principal;
3220
+ atNs: bigint;
3221
+ }
3222
+ export interface LogPage {
3223
+ firstAvailableSeq: bigint;
3224
+ head: Uint8Array | number[];
3225
+ page: Page_7;
3226
+ }
3227
+ export interface LogPosition {
3228
+ reads: bigint;
3229
+ record: bigint;
3230
+ }
3231
+ export interface MarketplacePaymentSignatures {
3232
+ marketplace: Principal;
3233
+ sharedSignedToday: bigint;
3234
+ limit: bigint;
3235
+ }
3236
+ export interface MemoryByteChunk {
3237
+ more: boolean;
3238
+ fileSize: bigint;
3239
+ bytes: Uint8Array | number[];
3240
+ }
3241
+ export interface MemoryEviction {
3242
+ evictSeq: bigint;
3243
+ fromVersion: bigint;
3244
+ evictedRoot: Uint8Array | number[];
3245
+ trigger:
3246
+ | { globalCap: null }
3247
+ | { thinTail: null }
3248
+ | { perFileCap: null }
3249
+ | { thinLogSpaced: null }
3250
+ | { policy: null };
3251
+ cause: { maxVersions: null } | { maxBytes: null };
3252
+ toVersion: bigint;
3253
+ }
3254
+ export interface MemoryFile {
3255
+ content: Uint8Array | number[];
3256
+ path: string;
3257
+ version: bigint;
3258
+ lastModifiedBy: Principal;
3259
+ lastModifiedAtNs: bigint;
3260
+ }
3261
+ export interface MemoryHistory {
3262
+ evictions: Array<MemoryEviction>;
3263
+ oldestRetainedVersion: bigint;
3264
+ everCount: bigint;
3265
+ retainedCount: bigint;
3266
+ versions: Array<MemoryVersionSummary>;
3267
+ evictedCount: bigint;
3268
+ }
3269
+ export interface MemoryLogChunkRef {
3270
+ hash: Uint8Array | number[];
3271
+ size: bigint;
3272
+ birthSeq: bigint;
3273
+ }
3274
+ export interface MemoryLogEvent {
3275
+ by: Principal;
3276
+ op: MemoryLogOp;
3277
+ seq: bigint;
3278
+ contentRoot: Uint8Array | number[];
3279
+ atNs: bigint;
3280
+ path: string;
3281
+ prev: Uint8Array | number[];
3282
+ size: bigint;
3283
+ version: bigint;
3284
+ }
3285
+ export type MemoryLogImportNote =
3286
+ | { legacyDelete: null }
3287
+ | {
3288
+ legacyTruncated: {
3289
+ prefixHash: Uint8Array | number[];
3290
+ storedBytes: bigint;
3291
+ };
3292
+ }
3293
+ | { legacyGap: { firstSurviving: bigint } }
3294
+ | {
3295
+ legacyUnreconstructable: {
3296
+ contentHash: Uint8Array | number[];
3297
+ reason: string;
3298
+ };
3299
+ }
3300
+ | { genesis: { boundTo: [] | [Uint8Array | number[]] } };
3301
+ export interface MemoryLogManifest {
3302
+ contentRoot: Uint8Array | number[];
3303
+ totalSize: bigint;
3304
+ chunks: Array<MemoryLogChunkRef>;
3305
+ }
3306
+ export type MemoryLogOp =
3307
+ | { set: { manifest: MemoryLogManifest } }
3308
+ | {
3309
+ exported: {
3310
+ toSeq: bigint;
3311
+ opsRoot: Uint8Array | number[];
3312
+ fromSeq: bigint;
3313
+ authorFilter: [] | [Principal];
3314
+ };
3315
+ }
3316
+ | { imported: MemoryLogImportNote }
3317
+ | { restore: { toVersion: bigint; manifest: MemoryLogManifest } }
3318
+ | {
3319
+ evict: {
3320
+ fromVersion: bigint;
3321
+ evictedRoot: Uint8Array | number[];
3322
+ toVersion: bigint;
3323
+ chunkCount: bigint;
3324
+ byteCount: bigint;
3325
+ };
3326
+ }
3327
+ | {
3328
+ append: {
3329
+ deltaHash: Uint8Array | number[];
3330
+ deltaSize: bigint;
3331
+ newSize: bigint;
3332
+ };
3333
+ }
3334
+ | { tombstone: null }
3335
+ | {
3336
+ condense: {
3337
+ toSeq: bigint;
3338
+ opsRoot: Uint8Array | number[];
3339
+ fromSeq: bigint;
3340
+ headAtBoundary: Uint8Array | number[];
3341
+ opCount: bigint;
3342
+ };
3343
+ };
3344
+ export interface MemoryMaintainStatus {
3345
+ attachOk: boolean;
3346
+ attachDetail: string;
3347
+ totalEvictions: bigint;
3348
+ refusedQuota: string;
3349
+ more: boolean;
3350
+ lastEvictions: bigint;
3351
+ lastScrubbed: bigint;
3352
+ lastMaintainAtNs: [] | [bigint];
3353
+ totalFindings: bigint;
3354
+ refused: boolean;
3355
+ }
3356
+ export interface MemoryRangeExport {
3357
+ seq: bigint;
3358
+ toSeq: bigint;
3359
+ opsRoot: Uint8Array | number[];
3360
+ atNs: bigint;
3361
+ head: Uint8Array | number[];
3362
+ fromSeq: bigint;
3363
+ authorFilter: [] | [Principal];
3364
+ }
3365
+ export interface MemoryRetentionPolicy {
3366
+ entries: Array<[string, RetentionClassSpec]>;
3367
+ guards: Array<{ notBeforeNs: bigint; prefix: string }>;
3368
+ }
3369
+ export type MemorySource =
3370
+ | { sessionTranscript: null }
3371
+ | { human: null }
3372
+ | { fileSync: null }
3373
+ | { agentDerived: null }
3374
+ | { deterministic: null };
3375
+ export interface MemoryVersionSummary {
3376
+ by: Principal;
3377
+ seq: bigint;
3378
+ contentRoot: Uint8Array | number[];
3379
+ atNs: bigint;
3380
+ kind: { set: null } | { restore: null } | { append: null } | { tombstone: null };
3381
+ size: bigint;
3382
+ version: bigint;
3383
+ }
3384
+ export interface OwnerConsole {
3385
+ pendingApprovalCount: bigint;
3386
+ memoryKeyEpoch: bigint;
3387
+ owner: [] | [Principal];
3388
+ agentRevisablePathCount: bigint;
3389
+ protectedPathCount: bigint;
3390
+ cyclesBalance: bigint;
3391
+ unknownSessionRefusals: bigint;
3392
+ }
3393
+ export interface OwnerRow {
3394
+ pairedDay: bigint;
3395
+ lastPaymentDay: [] | [bigint];
3396
+ root: Principal;
3397
+ weeks: bigint;
3398
+ produced: bigint;
3399
+ firstPaymentDay: [] | [bigint];
3400
+ }
3401
+ export interface OwnershipTransfer {
3402
+ to: Principal;
3403
+ atNs: bigint;
3404
+ from: [] | [Principal];
3405
+ authorizedBy: Principal;
3406
+ }
3407
+ export interface Page {
3408
+ total: bigint;
3409
+ withheld: bigint;
3410
+ items: Array<Repudiation>;
3411
+ }
3412
+ export interface Page_1 {
3413
+ total: bigint;
3414
+ withheld: bigint;
3415
+ items: Array<AuditEntry>;
3416
+ }
3417
+ export interface Page_10 {
3418
+ total: bigint;
3419
+ withheld: bigint;
3420
+ items: Array<GuardianRecord>;
3421
+ }
3422
+ export interface Page_11 {
3423
+ total: bigint;
3424
+ withheld: bigint;
3425
+ items: Array<{ activeFromNs: bigint; address: string }>;
3426
+ }
3427
+ export interface Page_12 {
3428
+ total: bigint;
3429
+ withheld: bigint;
3430
+ items: Array<RegisteredType>;
3431
+ }
3432
+ export interface Page_13 {
3433
+ total: bigint;
3434
+ withheld: bigint;
3435
+ items: Array<string>;
3436
+ }
3437
+ export interface Page_14 {
3438
+ total: bigint;
3439
+ withheld: bigint;
3440
+ items: Array<CycleSnapshot>;
3441
+ }
3442
+ export interface Page_15 {
3443
+ total: bigint;
3444
+ withheld: bigint;
3445
+ items: Array<CondenseCheckpointRow>;
3446
+ }
3447
+ export interface Page_16 {
3448
+ total: bigint;
3449
+ withheld: bigint;
3450
+ items: Array<BearerToken>;
3451
+ }
3452
+ export interface Page_17 {
3453
+ total: bigint;
3454
+ withheld: bigint;
3455
+ items: Array<BackupMetadata>;
3456
+ }
3457
+ export interface Page_18 {
3458
+ total: bigint;
3459
+ withheld: bigint;
3460
+ items: Array<{ status: AgentStatus; principal: Principal; name: string }>;
3461
+ }
3462
+ export interface Page_19 {
3463
+ total: bigint;
3464
+ withheld: bigint;
3465
+ items: Array<AgentRecord>;
3466
+ }
3467
+ export interface Page_2 {
3468
+ total: bigint;
3469
+ withheld: bigint;
3470
+ items: Array<PurgedAgent>;
3471
+ }
3472
+ export interface Page_20 {
3473
+ total: bigint;
3474
+ withheld: bigint;
3475
+ items: Array<ActivitySnapshot>;
3476
+ }
3477
+ export interface Page_21 {
3478
+ total: bigint;
3479
+ withheld: bigint;
3480
+ items: Array<OwnerRow>;
3481
+ }
3482
+ export interface Page_3 {
3483
+ total: bigint;
3484
+ withheld: bigint;
3485
+ items: Array<AgentPaymentSignatures>;
3486
+ }
3487
+ export interface Page_4 {
3488
+ total: bigint;
3489
+ withheld: bigint;
3490
+ items: Array<OwnershipTransfer>;
3491
+ }
3492
+ export interface Page_5 {
3493
+ total: bigint;
3494
+ withheld: bigint;
3495
+ items: Array<EngramSessionState>;
3496
+ }
3497
+ export interface Page_6 {
3498
+ total: bigint;
3499
+ withheld: bigint;
3500
+ items: Array<ApprovalRequest>;
3501
+ }
3502
+ export interface Page_7 {
3503
+ total: bigint;
3504
+ withheld: bigint;
3505
+ items: Array<MemoryLogEvent>;
3506
+ }
3507
+ export interface Page_8 {
3508
+ total: bigint;
3509
+ withheld: bigint;
3510
+ items: Array<{ path: string; version: bigint; lastModifiedAtNs: bigint }>;
3511
+ }
3512
+ export interface Page_9 {
3513
+ total: bigint;
3514
+ withheld: bigint;
3515
+ items: Array<ExportReceiptRow>;
3516
+ }
3517
+ export interface Pairing {
3518
+ agent: AgentRecord;
3519
+ trackRecord: TrackRecordNotice;
3520
+ }
3521
+ export interface PaymentSignature {
3522
+ signature: Uint8Array | number[];
3523
+ asset: [] | [string];
3524
+ publicKey: [] | [Uint8Array | number[]];
3525
+ scheme: string;
3526
+ network: string;
3527
+ sender: string;
3528
+ nonce: Uint8Array | number[];
3529
+ authorization: [] | [Eip3009Authorization];
3530
+ }
3531
+ export interface PaymentSignatureCounts {
3532
+ day: bigint;
3533
+ marketplace: [] | [MarketplacePaymentSignatures];
3534
+ agents: Page_3;
3535
+ limit: bigint;
3536
+ }
3537
+ export interface PurgedAgent {
3538
+ principal: Principal;
3539
+ pairedAtNs: bigint;
3540
+ name: string;
3541
+ root: Principal;
3542
+ enrolledKey: Principal;
3543
+ ended: AgentEnding;
3544
+ invite: string;
3545
+ purgedAtNs: bigint;
3546
+ }
3547
+ export interface RailHealth {
3548
+ sessionsExpired: bigint;
3549
+ sessionsClosed: bigint;
3550
+ paidVouchersConsumed: bigint;
3551
+ escrowOpen: [] | [bigint];
3552
+ sessionsOpen: bigint;
3553
+ sessionsClosing: bigint;
3554
+ cycles: bigint;
3555
+ sendHeadroom: bigint;
3556
+ memoryBytes: bigint;
3557
+ freezeReservation: bigint;
3558
+ unknownSessionRefusals: bigint;
3559
+ }
3560
+ export interface ReceiptPage {
3561
+ firstAvailableSeq: bigint;
3562
+ page: Page_9;
3563
+ scannedThroughSeq: bigint;
3564
+ }
3565
+ export interface RegisteredType {
3566
+ primaryType: string;
3567
+ encodeTypeString: string;
3568
+ cooloffEndsAtNs: bigint;
3569
+ domainName: string;
3570
+ typeId: Uint8Array | number[];
3571
+ verifyingContract: string;
3572
+ dailySignCap: bigint;
3573
+ fields: Array<[string, string]>;
3574
+ domainSeparator: Uint8Array | number[];
3575
+ destinationFields: Array<string>;
3576
+ authorityClass: AuthorityClass;
3577
+ typeHash: Uint8Array | number[];
3578
+ registeredAtNs: bigint;
3579
+ chainId: bigint;
3580
+ domainVersion: string;
3581
+ ackIrrevocable: boolean;
3582
+ }
3583
+ export interface Repudiation {
3584
+ atNs: bigint;
3585
+ path: string;
3586
+ auditId: bigint;
3587
+ version: bigint;
3588
+ reason: string;
3589
+ }
3590
+ export interface ResetReport {
3591
+ agentsRemoved: bigint;
3592
+ agentsPurged: bigint;
3593
+ guardiansRemoved: bigint;
3594
+ filesCleared: bigint;
3595
+ }
3596
+ export type Result = { Ok: WriteReceipt } | { Err: Error };
3597
+ export type Result_1 = { Ok: null } | { Err: Error };
3598
+ export type Result_10 = { Ok: BackupRetentionReport } | { Err: Error };
3599
+ export type Result_11 = { Ok: MemoryFile } | { Err: Error };
3600
+ export type Result_12 = { Ok: SessionContext } | { Err: Error };
3601
+ export type Result_13 = { Ok: ResyncReport } | { Err: Error };
3602
+ export type Result_14 = { Ok: ResetReport } | { Err: Error };
3603
+ export type Result_15 = { Ok: GuardianRecord } | { Err: Error };
3604
+ export type Result_16 = { Ok: MemoryByteChunk } | { Err: Error };
3605
+ export type Result_17 = { Ok: Array<BatchReadItem> } | { Err: Error };
3606
+ export type Result_18 = { Ok: CondensePreview } | { Err: Error };
3607
+ export type Result_19 = { Ok: Pairing } | { Err: Error };
3608
+ export type Result_2 = { Ok: ControlHandover } | { Err: Error };
3609
+ export type Result_20 = { Ok: EngramSessionState } | { Err: Error };
3610
+ export type Result_21 = { Ok: Principal } | { Err: Error };
3611
+ export type Result_22 = { Ok: Page } | { Err: Error };
3612
+ export type Result_23 = { Ok: Page_1 } | { Err: Error };
3613
+ export type Result_24 = { Ok: Page_2 } | { Err: Error };
3614
+ export type Result_25 = { Ok: PaymentSignatureCounts } | { Err: Error };
3615
+ export type Result_26 = { Ok: Page_4 } | { Err: Error };
3616
+ export type Result_27 = { Ok: Page_5 } | { Err: Error };
3617
+ export type Result_28 = { Ok: Page_6 } | { Err: Error };
3618
+ export type Result_29 = { Ok: LogPage } | { Err: Error };
3619
+ export type Result_3 = { Ok: X402SignOutcome } | { Err: Error };
3620
+ export type Result_30 = { Ok: Page_8 } | { Err: Error };
3621
+ export type Result_31 = { Ok: ReceiptPage } | { Err: Error };
3622
+ export type Result_32 = { Ok: Page_10 } | { Err: Error };
3623
+ export type Result_33 = { Ok: Page_11 } | { Err: Error };
3624
+ export type Result_34 = { Ok: Page_12 } | { Err: Error };
3625
+ export type Result_35 = { Ok: Page_13 } | { Err: Error };
3626
+ export type Result_36 = { Ok: Page_14 } | { Err: Error };
3627
+ export type Result_37 = { Ok: CheckpointPage } | { Err: Error };
3628
+ export type Result_38 = { Ok: Page_16 } | { Err: Error };
3629
+ export type Result_39 = { Ok: Page_17 } | { Err: Error };
3630
+ export type Result_4 = { Ok: Eip712SignatureOut } | { Err: Error };
3631
+ export type Result_40 = { Ok: Page_18 } | { Err: Error };
3632
+ export type Result_41 = { Ok: Page_19 } | { Err: Error };
3633
+ export type Result_42 = { Ok: Page_20 } | { Err: Error };
3634
+ export type Result_43 = { Ok: string } | { Err: Error };
3635
+ export type Result_44 = { Ok: boolean } | { Err: Error };
3636
+ export type Result_45 = { Ok: [] | [string] } | { Err: Error };
3637
+ export type Result_46 = { Ok: WorldIdRpContext } | { Err: Error };
3638
+ export type Result_47 = { Ok: WorldIdConfig } | { Err: Error };
3639
+ export type Result_48 = { Ok: WalletBalances } | { Err: Error };
3640
+ export type Result_49 = { Ok: StorageReport } | { Err: Error };
3641
+ export type Result_5 = { Ok: SignatureCounts } | { Err: Error };
3642
+ export type Result_50 = { Ok: SpendingPolicy } | { Err: Error };
3643
+ export type Result_51 = { Ok: SpendCeiling } | { Err: Error };
3644
+ export type Result_52 = { Ok: SigningFloorStatus } | { Err: Error };
3645
+ export type Result_53 = { Ok: { paths: Array<string> } } | { Err: Error };
3646
+ export type Result_54 = { Ok: OwnerConsole } | { Err: Error };
3647
+ export type Result_55 = { Ok: MemoryRetentionPolicy } | { Err: Error };
3648
+ export type Result_56 = { Ok: MemoryHistory } | { Err: Error };
3649
+ export type Result_57 = { Ok: AlertStatus } | { Err: Error };
3650
+ export type Result_58 = { Ok: EvmAddresses } | { Err: Error };
3651
+ export type Result_59 = { Ok: Uint8Array | number[] } | { Err: Error };
3652
+ export type Result_6 = { Ok: RailHealth } | { Err: Error };
3653
+ export type Result_60 = { Ok: ChildOpening } | { Err: Error };
3654
+ export type Result_61 = { Ok: ChildAllowanceRow } | { Err: Error };
3655
+ export type Result_62 = { Ok: BackupMetadata } | { Err: Error };
3656
+ export type Result_63 = { Ok: AgentWriteReview } | { Err: Error };
3657
+ export type Result_64 = { Ok: Page_21 } | { Err: Error };
3658
+ export type Result_66 = { Ok: MemoryRangeExport } | { Err: Error };
3659
+ export type Result_67 = { Ok: CondenseResult } | { Err: Error };
3660
+ export type Result_68 = { Ok: { activatesAtNs: bigint } } | { Err: Error };
3661
+ export type Result_69 = { Ok: Eip712Registration } | { Err: Error };
3662
+ export type Result_7 = { Ok: Array<Seat> } | { Err: Error };
3663
+ export type Result_70 = { Ok: AgentRecord } | { Err: Error };
3664
+ export type Result_8 = { Ok: bigint } | { Err: Error };
3665
+ export type Result_9 = { Ok: SignedTransaction } | { Err: Error };
3666
+ export interface ResyncReport {
3667
+ startsAcknowledged: bigint;
3668
+ cannotBeRecorded: Array<UnrecordableEngagement>;
3669
+ endingsAcknowledged: bigint;
3670
+ notRecorded: Array<{
3671
+ why: string;
3672
+ principal: Principal;
3673
+ root: Principal;
3674
+ event: string;
3675
+ }>;
3676
+ }
3677
+ export type RetentionClassSpec =
3678
+ | { vault: null }
3679
+ | {
3680
+ working: {
3681
+ maxVersions: [] | [bigint];
3682
+ maxBytes: [] | [bigint];
3683
+ thinning: { tail: null } | { logSpaced: { denseTail: bigint } };
3684
+ };
3685
+ };
3686
+ export type Role =
3687
+ | { Anonymous: null }
3688
+ | { Viewer: null }
3689
+ | { Engram: null }
3690
+ | { Root: null }
3691
+ | { Buyer: null }
3692
+ | { WasmAdmin: null }
3693
+ | { Guardian: null }
3694
+ | { Seller: null }
3695
+ | { Admin: null }
3696
+ | { Agent: null }
3697
+ | { Other: null }
3698
+ | { Owner: null };
3699
+ export interface Seat {
3700
+ pairedDay: bigint;
3701
+ lastPaymentDay: [] | [bigint];
3702
+ weeks: bigint;
3703
+ produced: bigint;
3704
+ firstPaymentDay: [] | [bigint];
3705
+ }
3706
+ export interface ServiceEntry {
3707
+ endpoint: string;
3708
+ name: string;
3709
+ version: string;
3710
+ domains: Array<string>;
3711
+ skills: Array<string>;
3712
+ }
3713
+ export interface SessionConfig {
3714
+ autoClose: boolean;
3715
+ idleTimeout: [] | [bigint];
3716
+ maxDeposit: bigint;
3717
+ }
3718
+ export interface SessionContext {
3719
+ files: Array<MemoryFile>;
3720
+ totalFiles: bigint;
3721
+ truncated: boolean;
3722
+ includedFiles: bigint;
3723
+ totalBytes: bigint;
3724
+ }
3725
+ export interface SessionIntent {
3726
+ token: string;
3727
+ costPerCall: [] | [bigint];
3728
+ minDeposit: [] | [bigint];
3729
+ recipient: string;
3730
+ network: string;
3731
+ description: [] | [string];
3732
+ expiryNs: bigint;
3733
+ suggestedDeposit: bigint;
3734
+ }
3735
+ export interface SignatureCounts {
3736
+ total: bigint;
3737
+ byCaller: Array<CallerSignatureCount>;
3738
+ }
3739
+ export interface SignedAuthorization {
3740
+ paidAmount: bigint;
3741
+ authorization: {
3742
+ to: string;
3743
+ signature: string;
3744
+ value: bigint;
3745
+ from: string;
3746
+ validAfter: bigint;
3747
+ nonce: string;
3748
+ validBefore: bigint;
3749
+ };
3750
+ header: string;
3751
+ }
3752
+ export interface SignedTransaction {
3753
+ txHash: string;
3754
+ rawTx: string;
3755
+ }
3756
+ export interface SigningFloorStatus {
3757
+ floor: bigint;
3758
+ signaturesAboveFloor: bigint;
3759
+ balance: bigint;
3760
+ perSignature: bigint;
3761
+ }
3762
+ export interface SpendCeiling {
3763
+ spentToday: bigint;
3764
+ maxPerDay: [] | [bigint];
3765
+ }
3766
+ export interface SpendingPolicy {
3767
+ maxSessionDeposit: [] | [bigint];
3768
+ blockedCallers: [] | [Array<Principal>];
3769
+ maxPerDay: [] | [bigint];
3770
+ maxSessionDuration: [] | [bigint];
3771
+ sessionIdleTimeout: [] | [bigint];
3772
+ rateLimitPerMinute: [] | [bigint];
3773
+ maxPerTransaction: [] | [bigint];
3774
+ allowedCallers: [] | [Array<Principal>];
3775
+ maxConcurrentSessions: [] | [bigint];
3776
+ }
3777
+ export interface StorageReport {
3778
+ sessionFilesSize: bigint;
3779
+ totalFiles: bigint;
3780
+ memoryFilesSize: bigint;
3781
+ totalContentSize: bigint;
3782
+ backupCount: bigint;
3783
+ memoryFilesCount: bigint;
3784
+ versionHistorySize: bigint;
3785
+ fileLimit: bigint;
3786
+ backupSize: bigint;
3787
+ auditLogSize: bigint;
3788
+ versionHistoryCount: bigint;
3789
+ sessionFilesCount: bigint;
3790
+ }
3791
+ export interface TimerHealth {
3792
+ jobExpiryFastMode: boolean;
3793
+ jobExpiryArmed: boolean;
3794
+ alertTimerArmed: boolean;
3795
+ sessionExpiryArmed: boolean;
3796
+ }
3797
+ export type TokenAmount = { Icp: bigint } | { Ckusdc: bigint } | { Ckusdt: bigint };
3798
+ export type TrackRecordNotice = { Recorded: null } | { NotRecorded: string };
3799
+ export interface UnrecordableEngagement {
3800
+ principal: Principal;
3801
+ root: Principal;
3802
+ ended: AgentEnding;
3803
+ invite: string;
3804
+ }
3805
+ export interface Voucher {
3806
+ signature: Uint8Array | number[];
3807
+ sessionId: string;
3808
+ sequence: bigint;
3809
+ cumulativeAmount: bigint;
3810
+ }
3811
+ export interface WalletBalances {
3812
+ icpE8s: bigint;
3813
+ ckusdcE6s: bigint;
3814
+ ckusdtE6s: bigint;
3815
+ cycles: bigint;
3816
+ }
3817
+ export interface WorldIdConfig {
3818
+ action: string;
3819
+ appId: string;
3820
+ rpId: string;
3821
+ configured: boolean;
3822
+ }
3823
+ export interface WorldIdRpContext {
3824
+ signature: string;
3825
+ expiresAt: bigint;
3826
+ createdAt: bigint;
3827
+ rpId: string;
3828
+ nonce: string;
3829
+ }
3830
+ export interface WriteReceipt {
3831
+ seq: bigint;
3832
+ head: Uint8Array | number[];
3833
+ version: bigint;
3834
+ }
3835
+ export type X402SignOutcome =
3836
+ { ApprovalPending: ApprovalRequest } | { Signed: SignedAuthorization };
3837
+ export interface _SERVICE extends Engram {}
3838
+ export declare const idlFactory: IDL.InterfaceFactory;
3839
+ export declare const init: (args: { IDL: typeof IDL }) => IDL.Type[];