@engramx/idl 0.16.0-rc.13 → 0.16.0-rc.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/engram.did CHANGED
@@ -5,8 +5,14 @@ type X402SignOutcome =
5
5
  };
6
6
  type WriteReceipt =
7
7
  record {
8
+ atNs: int;
9
+ contentRoot: blob;
8
10
  head: blob;
11
+ prev: blob;
12
+ recordId: nat;
13
+ recordPrev: blob;
9
14
  seq: nat;
15
+ size: nat;
10
16
  version: nat;
11
17
  };
12
18
  type WorldIdRpContext =
@@ -168,6 +174,12 @@ type Seat =
168
174
  produced: nat;
169
175
  weeks: nat64;
170
176
  };
177
+ type SealedEntry =
178
+ record {
179
+ digest: blob;
180
+ entryHash: blob;
181
+ id: nat;
182
+ };
171
183
  type Role =
172
184
  variant {
173
185
  Admin;
@@ -220,11 +232,16 @@ type Result_8 =
220
232
  Err: Error;
221
233
  Ok: SignedTransaction;
222
234
  };
223
- type Result_71 =
235
+ type Result_72 =
224
236
  variant {
225
237
  Err: Error;
226
238
  Ok: AgentRecord;
227
239
  };
240
+ type Result_71 =
241
+ variant {
242
+ Err: Error;
243
+ Ok: record {activatesAtNs: int;};
244
+ };
228
245
  type Result_70 =
229
246
  variant {
230
247
  Err: Error;
@@ -238,47 +255,47 @@ type Result_7 =
238
255
  type Result_69 =
239
256
  variant {
240
257
  Err: Error;
241
- Ok: record {activatesAtNs: int;};
258
+ Ok: CondenseResult;
242
259
  };
243
260
  type Result_68 =
244
261
  variant {
245
262
  Err: Error;
246
- Ok: CondenseResult;
263
+ Ok: MemoryRangeExport;
247
264
  };
248
- type Result_67 =
265
+ type Result_66 =
249
266
  variant {
250
267
  Err: Error;
251
- Ok: MemoryRangeExport;
268
+ Ok: Page_21;
252
269
  };
253
270
  type Result_65 =
254
271
  variant {
255
272
  Err: Error;
256
- Ok: Page_21;
273
+ Ok: AgentWriteReview;
257
274
  };
258
275
  type Result_64 =
259
276
  variant {
260
277
  Err: Error;
261
- Ok: AgentWriteReview;
278
+ Ok: BackupMetadata;
262
279
  };
263
280
  type Result_63 =
264
281
  variant {
265
282
  Err: Error;
266
- Ok: BackupMetadata;
283
+ Ok: ChildAllowanceRow;
267
284
  };
268
285
  type Result_62 =
269
286
  variant {
270
287
  Err: Error;
271
- Ok: ChildAllowanceRow;
288
+ Ok: ChildOpening;
272
289
  };
273
290
  type Result_61 =
274
291
  variant {
275
292
  Err: Error;
276
- Ok: ChildOpening;
293
+ Ok: blob;
277
294
  };
278
295
  type Result_60 =
279
296
  variant {
280
297
  Err: Error;
281
- Ok: blob;
298
+ Ok: EvmAddresses;
282
299
  };
283
300
  type Result_6 =
284
301
  variant {
@@ -288,52 +305,52 @@ type Result_6 =
288
305
  type Result_59 =
289
306
  variant {
290
307
  Err: Error;
291
- Ok: EvmAddresses;
308
+ Ok: AlertStatus;
292
309
  };
293
310
  type Result_58 =
294
311
  variant {
295
312
  Err: Error;
296
- Ok: AlertStatus;
313
+ Ok: MemoryHistory;
297
314
  };
298
315
  type Result_57 =
299
316
  variant {
300
317
  Err: Error;
301
- Ok: MemoryHistory;
318
+ Ok: MemoryRetentionPolicy;
302
319
  };
303
320
  type Result_56 =
304
321
  variant {
305
322
  Err: Error;
306
- Ok: MemoryRetentionPolicy;
323
+ Ok: OwnerConsole;
307
324
  };
308
325
  type Result_55 =
309
326
  variant {
310
327
  Err: Error;
311
- Ok: OwnerConsole;
328
+ Ok: record {paths: vec text;};
312
329
  };
313
330
  type Result_54 =
314
331
  variant {
315
332
  Err: Error;
316
- Ok: record {paths: vec text;};
333
+ Ok: SigningFloorStatus;
317
334
  };
318
335
  type Result_53 =
319
336
  variant {
320
337
  Err: Error;
321
- Ok: SigningFloorStatus;
338
+ Ok: SpendCeiling;
322
339
  };
323
340
  type Result_52 =
324
341
  variant {
325
342
  Err: Error;
326
- Ok: SpendCeiling;
343
+ Ok: SpendingPolicy;
327
344
  };
328
345
  type Result_51 =
329
346
  variant {
330
347
  Err: Error;
331
- Ok: SpendingPolicy;
348
+ Ok: StorageReport;
332
349
  };
333
350
  type Result_50 =
334
351
  variant {
335
352
  Err: Error;
336
- Ok: StorageReport;
353
+ Ok: WalletBalances;
337
354
  };
338
355
  type Result_5 =
339
356
  variant {
@@ -343,47 +360,47 @@ type Result_5 =
343
360
  type Result_49 =
344
361
  variant {
345
362
  Err: Error;
346
- Ok: WalletBalances;
363
+ Ok: WorldIdConfig;
347
364
  };
348
365
  type Result_48 =
349
366
  variant {
350
367
  Err: Error;
351
- Ok: WorldIdConfig;
368
+ Ok: WorldIdRpContext;
352
369
  };
353
370
  type Result_47 =
354
371
  variant {
355
372
  Err: Error;
356
- Ok: WorldIdRpContext;
373
+ Ok: opt text;
357
374
  };
358
375
  type Result_46 =
359
376
  variant {
360
377
  Err: Error;
361
- Ok: opt text;
378
+ Ok: bool;
362
379
  };
363
380
  type Result_45 =
364
381
  variant {
365
382
  Err: Error;
366
- Ok: bool;
383
+ Ok: text;
367
384
  };
368
385
  type Result_44 =
369
386
  variant {
370
387
  Err: Error;
371
- Ok: text;
388
+ Ok: Page_20;
372
389
  };
373
390
  type Result_43 =
374
391
  variant {
375
392
  Err: Error;
376
- Ok: Page_20;
393
+ Ok: Page_19;
377
394
  };
378
395
  type Result_42 =
379
396
  variant {
380
397
  Err: Error;
381
- Ok: Page_19;
398
+ Ok: Page_18;
382
399
  };
383
400
  type Result_41 =
384
401
  variant {
385
402
  Err: Error;
386
- Ok: Page_18;
403
+ Ok: RecordPage;
387
404
  };
388
405
  type Result_40 =
389
406
  variant {
@@ -580,27 +597,13 @@ type Repudiation =
580
597
  reason: text;
581
598
  version: nat;
582
599
  };
583
- type RegisteredType =
600
+ type RecordPage =
584
601
  record {
585
- ackIrrevocable: bool;
586
- authorityClass: AuthorityClass;
587
- chainId: nat;
588
- cooloffEndsAtNs: int;
589
- dailySignCap: nat;
590
- destinationFields: vec text;
591
- domainName: text;
592
- domainSeparator: vec nat8;
593
- domainVersion: text;
594
- encodeTypeString: text;
595
- fields: vec record {
596
- text;
597
- text;
598
- };
599
- primaryType: text;
600
- registeredAtNs: int;
601
- typeHash: vec nat8;
602
- typeId: blob;
603
- verifyingContract: text;
602
+ hashFirstFrom: nat;
603
+ items: vec AuditEntry;
604
+ ringFloor: nat;
605
+ sealed: vec SealedEntry;
606
+ total: nat;
604
607
  };
605
608
  type ReceiptPage =
606
609
  record {
@@ -769,16 +772,13 @@ type Page_13 =
769
772
  };
770
773
  type Page_12 =
771
774
  record {
772
- items: vec RegisteredType;
775
+ items: vec Eip712Destination;
773
776
  total: nat;
774
777
  withheld: nat;
775
778
  };
776
779
  type Page_11 =
777
780
  record {
778
- items: vec record {
779
- activeFromNs: int;
780
- address: text;
781
- };
781
+ items: vec Eip712TypeView;
782
782
  total: nat;
783
783
  withheld: nat;
784
784
  };
@@ -1181,7 +1181,7 @@ type Engram =
1181
1181
  /// nomination names. That check compares the caller inside the module, where
1182
1182
  /// test/key-replacement.test.mo runs it; this body names no roster gate, because the caller holds
1183
1183
  /// no role here until the move.
1184
- acceptAgentKeyNomination: (agentKey: principal) -> (Result_71);
1184
+ acceptAgentKeyNomination: (agentKey: principal) -> (Result_72);
1185
1185
  /// Consensus transform for the alert webhook outcall: collapse the response to status-only so
1186
1186
  /// replicas agree regardless of response headers/body (we only care that the POST landed 2xx).
1187
1187
  ///
@@ -1194,9 +1194,32 @@ type Engram =
1194
1194
  context: blob;
1195
1195
  response: HttpRequestResult;
1196
1196
  }) -> (HttpRequestResult) query;
1197
+ /// Owner-managed destination allowlist (D7). Additions LOOSEN and wait 24h; removals TIGHTEN
1198
+ /// and apply instantly — the ratified asymmetry, applied to the one mutable policy surface.
1199
+ ///
1200
+ /// ⟨2026-10-14, the owner's ruling 4A⟩ ONE LIST PER REGISTERED ACTION. `addEvmWithdrawDestination`,
1201
+ /// `removeEvmWithdrawDestination` and `listEvmWithdrawDestinations` — one list for every action —
1202
+ /// are REMOVED; these three take the action's `typeId`. Same rules, per action: the owner only; an
1203
+ /// addition activates after 24 hours and is refused while payments are frozen; a removal is instant
1204
+ /// and works while frozen; a value is 1–128 characters (an address, or a venue value such as an
1205
+ /// account name). The action must be registered: a destination list belongs to an action, and a
1206
+ /// list for no action would be a value nothing checks. The caller is the owner's app.
1207
+ addEip712Destination: (typeId: blob, value: text) -> (Result_71);
1197
1208
  /// Register a typed-data shape as signable. Owner-only, freeze-gated (a registration is a grant
1198
1209
  /// of FUTURE authority — a frozen engram must not be able to widen what it can sign), and the
1199
1210
  /// shape is IMMUTABLE: any change mints a new typeId.
1211
+ ///
1212
+ /// ⟨2026-10-14, the owner's rulings 3A and 5A⟩ ONE BAR FOR EVERY REGISTRATION — the class the owner
1213
+ /// names is stored as a label and decides nothing. Every registration: records the irrevocability
1214
+ /// acknowledgement (`ackIrrevocable = true`); has no opaque field (`bytes`, `bytes1..32`); names at
1215
+ /// least one destination field OR carries a must-equal rule; passes the watchers — an owner alert
1216
+ /// webhook set, enabled AND with its money class on, and an `#Active` guardian holding
1217
+ /// `canFreezePayments`; and waits `Eip712Policy.COOLOFF_NS` (72 hours). It may carry per-field
1218
+ /// rules (`fieldRules`: "at most N" read as a plain decimal with D places, "must equal X"), which
1219
+ /// are part of the registered shape — inside the typeId, stored in `eip712FieldRules`, enforced in
1220
+ /// `eip712SignFor` before the cap reservation. Before this, a withdrawal registered as `#standard`
1221
+ /// needed no webhook, no guardian and no destination field, waited one hour, and signed to any
1222
+ /// address. Intrinsic checks still come first and the watchers last (the 2026-08-06 re-ordering).
1200
1223
  addEip712Type: (spec:
1201
1224
  record {
1202
1225
  ackIrrevocable: bool;
@@ -1211,6 +1234,10 @@ type Engram =
1211
1234
  destinationFields: vec text;
1212
1235
  domainName: text;
1213
1236
  domainVersion: text;
1237
+ fieldRules: vec record {
1238
+ text;
1239
+ Eip712FieldRule;
1240
+ };
1214
1241
  fields: vec record {
1215
1242
  text;
1216
1243
  text;
@@ -1218,9 +1245,6 @@ type Engram =
1218
1245
  primaryType: text;
1219
1246
  verifyingContract: text;
1220
1247
  }) -> (Result_70);
1221
- /// Owner-managed destination allowlist (D7). Additions LOOSEN and wait 24h; removals TIGHTEN
1222
- /// and apply instantly — the ratified asymmetry, applied to the one mutable policy surface.
1223
- addEvmWithdrawDestination: (dest: text) -> (Result_69);
1224
1248
  /// ⟨0.16.0, L1⟩ THE ROLE-CONFLICT ARM, and why three refusals here are not the same refusal.
1225
1249
  ///
1226
1250
  /// This method had five distinct ways to say no through one `text`, and a caller could only tell
@@ -1262,7 +1286,7 @@ type Engram =
1262
1286
  /// Gated on requireWritesNotPaused — unlike the export. This one destroys retained entries, which
1263
1287
  /// is exactly what a guardian pause exists to hold. No action alert is raised: the operation is
1264
1288
  /// owner-initiated, owner-only, and already chained into the audit log.
1265
- applyCondense: (toSeq: nat) -> (Result_68);
1289
+ applyCondense: (toSeq: nat) -> (Result_69);
1266
1290
  /// Owner-only: activate a guardian who has registered against an invite.
1267
1291
  ///
1268
1292
  /// Until this call the guardian is `#Pending` and can do NOTHING — registering is a claim, this
@@ -1333,13 +1357,13 @@ type Engram =
1333
1357
  ///
1334
1358
  /// The write half also refuses while writes are PAUSED.
1335
1359
  backupInit: (dbType: text, backupType: BackupType, parentBackupId:
1336
- opt text, sha256: text, backupLabel: opt text) -> (Result_44);
1360
+ opt text, sha256: text, backupLabel: opt text) -> (Result_45);
1337
1361
  /// Read one chunk of a finalized backup, by index.
1338
1362
  ///
1339
1363
  /// ⚠ GATED ON `read_backup`, which is NOT the permission the upload half uses — that one is
1340
1364
  /// `canAppendMemory`. Holding one says nothing about the other, deliberately: taking a backup and
1341
1365
  /// carrying it away are different authorities.
1342
- backupPullChunk: (backupId: text, chunkIndex: nat) -> (Result_60) query;
1366
+ backupPullChunk: (backupId: text, chunkIndex: nat) -> (Result_61) query;
1343
1367
  backupPushChunk: (backupId: text, chunkIndex: nat, data: blob) ->
1344
1368
  (Result_1);
1345
1369
  /// The OWNER cancels an agent's pending key nomination; the agent keeps its current key. Refused
@@ -1391,7 +1415,7 @@ type Engram =
1391
1415
  /// A principal that is already a GUARDIAN cannot become an agent — a guardian is an
1392
1416
  /// independent check on agents, so one wallet must not hold both.
1393
1417
  createAgentInvite: (name: text, permissions: AgentPermissions) ->
1394
- (Result_44);
1418
+ (Result_45);
1395
1419
  /// Owner-only: mint an invite for a GUARDIAN — an independent check on agents, not a
1396
1420
  /// co-owner and not a recovery agent.
1397
1421
  ///
@@ -1414,7 +1438,7 @@ type Engram =
1414
1438
  /// So an invite that fails to redeem for that reason is not a bad code. The rule exists because
1415
1439
  /// a check must be independent of the thing it checks.
1416
1440
  createGuardianInvite: (name: text, permissions: GuardianPermissions) ->
1417
- (Result_44);
1441
+ (Result_45);
1418
1442
  /// OWNER-ONLY deletion of a stored backup.
1419
1443
  ///
1420
1444
  /// ⚠ NOT THE SAME GATE AS THE REST OF THE FAMILY, and the asymmetry is deliberate: `backupInit`,
@@ -1455,7 +1479,7 @@ type Engram =
1455
1479
  /// situation rather than a safety measure. It IS gated on requireMemoryAttached: a store that
1456
1480
  /// failed its integrity check must not attest anything it cannot vouch for.
1457
1481
  exportMemoryRange: (fromSeq: nat, toSeq: nat, authorFilter:
1458
- opt principal) -> (Result_67);
1482
+ opt principal) -> (Result_68);
1459
1483
  /// ⟨0.16.0, L2.2 — renamed from `guardianFreezePayments`⟩ The prefix LIED about who may call it.
1460
1484
  /// The gate is `requireOwnerOrGuardian`, and an owner freezing their own payments is the ordinary
1461
1485
  /// case — the guardian is the exceptional one. A name that says otherwise sends an owner looking
@@ -1471,6 +1495,8 @@ type Engram =
1471
1495
  /// individual method's body finds nothing — the check is one level down.⟩
1472
1496
  /// · `addEip712Type` and `addEvmWithdrawDestination` — pre-staging for a later payout is the
1473
1497
  /// thing a brake most needs to stop, so the destination list is frozen along with the signing.
1498
+ /// ⟨2026-10-14, the owner's ruling 4A⟩ `addEvmWithdrawDestination` is removed; its place is
1499
+ /// `addEip712Destination` (one list per registered action), freeze-gated the same way.
1474
1500
  /// · `sessionReadMemory` and `sessionAppendMemory` — the paid-memory rail, money coming IN.
1475
1501
  ///
1476
1502
  /// AND WHAT IT DELIBERATELY DOES NOT, stated so the absence is not read as an oversight:
@@ -1487,7 +1513,7 @@ type Engram =
1487
1513
  /// before this one. If any of them is wrong, this comment is where the argument should happen.
1488
1514
  freezePayments: () -> (Result_1);
1489
1515
  /// Delivery status + config readback. Owner-only (the URL is a secret).
1490
- getActionAlertStatus: () -> (Result_58) query;
1516
+ getActionAlertStatus: () -> (Result_59) query;
1491
1517
  /// Agents need to know what they may revise, so they can read it too. Whole-value config, same
1492
1518
  /// carve-out as getProtectedPaths — and kept a SEPARATE method from it deliberately (L2.2): a
1493
1519
  /// protected path and a revisable path are opposite grants, and one accessor for both would be a
@@ -1495,7 +1521,7 @@ type Engram =
1495
1521
  ///
1496
1522
  /// Refusal reason preserved from the trap: a grant is a power, and its absence and its
1497
1523
  /// concealment are different facts.
1498
- getAgentRevisablePaths: () -> (Result_54) query;
1524
+ getAgentRevisablePaths: () -> (Result_55) query;
1499
1525
  /// OWNER-ONLY: every engagement's seat weeks on this engram, with the agent's root — the day it
1500
1526
  /// paired, the days of its first and last payment signature, a 64-week map whose bit 0 is the week
1501
1527
  /// of the last one, and how many were produced. Never an amount, a recipient or a nonce.
@@ -1506,7 +1532,7 @@ type Engram =
1506
1532
  /// order. Anyone else is refused by name (`#Refused getAgentSeatWeeks: …`), never answered with an
1507
1533
  /// empty page. Paged; `total` is every engagement ever paired here (a reset keeps the rows).
1508
1534
  /// Two rows can name one root: an agent paired again after it left is a second engagement.
1509
- getAgentSeatWeeks: (start: nat, limit: nat) -> (Result_65) query;
1535
+ getAgentSeatWeeks: (start: nat, limit: nat) -> (Result_66) query;
1510
1536
  /// Owner: everything written into this engram by someone other than the owner since the last
1511
1537
  /// markAgentWritesReviewed() — agent appends/revisions AND paid-session appends (see
1512
1538
  /// qualifiesForReview for why those two families are recognised differently).
@@ -1514,7 +1540,7 @@ type Engram =
1514
1540
  /// them — the UI must page (markAgentWritesReviewed(?lastShownId)) and must NOT present 200
1515
1541
  /// as a total. `earliest` discloses ring eviction — if cursor < earliest, entries between them
1516
1542
  /// aged out of the ring (the CHAIN still proves total count; this view can't show their bodies).
1517
- getAgentWriteReview: () -> (Result_64) query;
1543
+ getAgentWriteReview: () -> (Result_65) query;
1518
1544
  /// Why anchoring is or is not advancing. PUBLIC: ungated on purpose — detecting a stalled
1519
1545
  /// engram is the point, a gated read would fail-to-empty and hand a third party fabricated zeros,
1520
1546
  /// and none of these fields is a secret — `total` is already public via getCertifiedAuditHead.
@@ -1533,7 +1559,7 @@ type Engram =
1533
1559
  /// below serves the same head WITH the subnet certificate for a caller that needs to verify it
1534
1560
  /// was signed rather than asserted.
1535
1561
  getAuditHead: () -> (AuditHead) query;
1536
- getBackupMetadata: (backupId: text) -> (Result_63) query;
1562
+ getBackupMetadata: (backupId: text) -> (Result_64) query;
1537
1563
  /// The cashier this engram recognises as its rent biller — `null` until the registry pushes one.
1538
1564
  ///
1539
1565
  /// PUBLIC: a payer about to send money needs to know which cashier this engram will accept credit
@@ -1563,11 +1589,11 @@ type Engram =
1563
1589
  /// query's state writes are discarded when it returns, and the `denied` call first written here
1564
1590
  /// recorded nothing while reading as if it did. The refusal is loud in the reply instead. WHAT
1565
1591
  /// WOULD MAKE THIS WRONG: a reason to record who asked — then this becomes an update that says so.
1566
- getChildAllowance: (agentPrincipal: principal) -> (Result_62) query;
1592
+ getChildAllowance: (agentPrincipal: principal) -> (Result_63) query;
1567
1593
  /// Owner-only, Billing-class: what opening an engram costs this engram, the balance below which an
1568
1594
  /// agent's request is refused, the balance now, and every agent's allowance. The console's cost
1569
1595
  /// sentence reads it. Cycles are owner-class information, as on the owner's console read.
1570
- getChildOpening: () -> (Result_61) query;
1596
+ getChildOpening: () -> (Result_62) query;
1571
1597
  /// Derive the shared memory-encryption key, encrypted under the caller's transport
1572
1598
  /// public key. Gated to owner + read-agents (the same principals allowed to read
1573
1599
  /// memory). The client decrypts it locally with its transport secret key.
@@ -1592,7 +1618,7 @@ type Engram =
1592
1618
  /// cost. Stated here because L7 requires the reason be readable from the interface rather than
1593
1619
  /// inferred by opening the body — which is exactly what had to happen to write this line.
1594
1620
  getEncryptedMemoryKey: (epoch: opt nat, transportPublicKey: blob) ->
1595
- (Result_60);
1621
+ (Result_61);
1596
1622
  /// ⟨0.16.0, owner ruling 2026-08-20 — option (a)⟩ `x402Support` REPORTS THE RAIL, not a constant.
1597
1623
  ///
1598
1624
  /// The card's config hardcodes `x402Support = true`, answering a buyer's question with a fact
@@ -1687,7 +1713,7 @@ type Engram =
1687
1713
  /// It refuses rather than half-answers: if either address cannot be derived the reply is
1688
1714
  /// `#Err`, never a record carrying an empty string (ic402's `getEvmAddress` answers `""` on a
1689
1715
  /// failed derivation — that is fail-to-empty on a money surface, and it stops here).
1690
- getEvmAddress: () -> (Result_59);
1716
+ getEvmAddress: () -> (Result_60);
1691
1717
  /// The owner's OWN EVM address, if they registered one — distinct from `getEvmAddress`, which is
1692
1718
  /// the address this canister derives for itself.
1693
1719
  ///
@@ -1702,7 +1728,7 @@ type Engram =
1702
1728
  /// the management canister's `ecdsa_public_key`. A query cannot await, so the round-trip is the
1703
1729
  /// cost — stated here because L7 requires the reason be readable from the interface rather than
1704
1730
  /// inferred by opening the body.
1705
- getEvmSignerAddress: () -> (Result_44);
1731
+ getEvmSignerAddress: () -> (Result_45);
1706
1732
  /// PUBLIC: where this chain begins, for the stranger deciding whether to trust it.
1707
1733
  ///
1708
1734
  /// The fourth of the four evidence methods (`getAuditHead`, `getCertifiedAuditHead`,
@@ -1711,7 +1737,7 @@ type Engram =
1711
1737
  /// cannot verify it, and nothing here identifies anybody.
1712
1738
  getGenesisNote: () -> (GenesisNote) query;
1713
1739
  /// A guardian's own channel status (their URL is their secret — each guardian sees only theirs).
1714
- getGuardianAlertStatus: () -> (Result_58) query;
1740
+ getGuardianAlertStatus: () -> (Result_59) query;
1715
1741
  /// The market this engram will accept signing requests from — `null` until the registry pushes
1716
1742
  /// one at spawn, which is why `requireMarket` refuses fleet-wide today.
1717
1743
  ///
@@ -1741,7 +1767,7 @@ type Engram =
1741
1767
  /// never renumbered: the next page starts at the last version returned plus one. Defaults
1742
1768
  /// return the whole history of any file a pre-FD engram could have held.
1743
1769
  getMemoryHistory: (path: text, start: opt nat, max: opt nat) ->
1744
- (Result_57) query;
1770
+ (Result_58) query;
1745
1771
  /// PUBLIC: the epoch alone, and deliberately nothing else (rotation study D4). A `rotatedAt[]`
1746
1772
  /// history would be a public, fleet-enumerable feed of when each owner terminated a trust
1747
1773
  /// relationship — readable by, among others, the party just terminated.
@@ -1782,7 +1808,7 @@ type Engram =
1782
1808
  /// Refusal reasons of both merge: an empty policy reads as "nothing is capped, every version kept
1783
1809
  /// forever" — a claim about what this engram will DESTROY — and an empty guard list reads as
1784
1810
  /// "nothing is held back".
1785
- getMemoryRetentionPolicy: () -> (Result_56) query;
1811
+ getMemoryRetentionPolicy: () -> (Result_57) query;
1786
1812
  /// The metrics reader this engram answers — `null` until the spawning registry names one.
1787
1813
  ///
1788
1814
  /// PUBLIC: an owner deciding whether to switch the read off needs to know who it is, and anyone
@@ -1805,7 +1831,7 @@ type Engram =
1805
1831
  /// was `nat`, then widened to `opt nat` so a refusal could be `null`, which broke every published
1806
1832
  /// client (rule 4) and bought a masked answer nobody had asked for — the census could not even
1807
1833
  /// find a consumer that read the masked `0`. Behind a gate there is nobody to mask it from.
1808
- getOwnerConsole: () -> (Result_55) query;
1834
+ getOwnerConsole: () -> (Result_56) query;
1809
1835
  /// Owner + agents only (agents need it to avoid writing protected paths).
1810
1836
  ///
1811
1837
  /// A NAMED RECORD, not a Page: the setter replaces this list wholesale, so there is no window to
@@ -1817,7 +1843,7 @@ type Engram =
1817
1843
  /// path on this engram is protected", and an agent consults this list precisely to avoid
1818
1844
  /// writing one — so a fabricated empty here does not merely misinform, it invites the write the
1819
1845
  /// list exists to prevent.
1820
- getProtectedPaths: () -> (Result_54) query;
1846
+ getProtectedPaths: () -> (Result_55) query;
1821
1847
  /// Whether the metrics reader's read is answered — `true` from birth.
1822
1848
  ///
1823
1849
  /// PUBLIC: the promise that an owner can switch this read off can be checked only if the switch
@@ -1826,7 +1852,7 @@ type Engram =
1826
1852
  /// Owner-only, Billing-class: the signing floor, the balance, one signature's price, and how many
1827
1853
  /// payment signatures the balance carries above the floor before `signX402Payment` is refused by
1828
1854
  /// name. The same numbers the check uses, so Billing can say only what the engram enforces.
1829
- getSigningFloor: () -> (Result_53) query;
1855
+ getSigningFloor: () -> (Result_54) query;
1830
1856
  /// The registry that spawned this engram, if it recorded one.
1831
1857
  ///
1832
1858
  /// PUBLIC: it is the provenance claim. An engram asserting it is part of a fleet, under that
@@ -1843,7 +1869,7 @@ type Engram =
1843
1869
  /// configuration, and the engram-wide total would also tell one agent how much the others spent.
1844
1870
  /// A refusal names this method (`Gated.gatedResult`) rather than answering null/0 — a ceiling of
1845
1871
  /// "none" and a spend of 0 are both real answers, so a fabricated one would be read as fact.
1846
- getSpendCeiling: () -> (Result_52) query;
1872
+ getSpendCeiling: () -> (Result_53) query;
1847
1873
  /// Read the caps in force for a caller.
1848
1874
  ///
1849
1875
  /// OWNER-ONLY, and this is where it diverges from the market's inbound twin, which is public.
@@ -1851,8 +1877,8 @@ type Engram =
1851
1877
  /// Here the engram serves no 402s at all: these caps are the owner's private custody
1852
1878
  /// configuration, and publishing them would tell any caller exactly how large a signing request
1853
1879
  /// can be before it needs an approval nobody is watching for.
1854
- getSpendPolicy: (caller: opt principal) -> (Result_51) query;
1855
- getStorageStats: () -> (Result_50) query;
1880
+ getSpendPolicy: (caller: opt principal) -> (Result_52) query;
1881
+ getStorageStats: () -> (Result_51) query;
1856
1882
  /// Timer arm-state. PUBLIC and deliberately so: these timers are self-arming to save cycles,
1857
1883
  /// and an optimisation nobody can verify is an optimisation nobody should trust. Cheap to read,
1858
1884
  /// leaks nothing (booleans about our own scheduling).
@@ -1923,12 +1949,12 @@ type Engram =
1923
1949
  /// ⟨L7⟩ MARKER ADDED 2026-08-23, reasoning above UNCHANGED — this block already said "Stays an
1924
1950
  /// UPDATE, marked per L7: it awaits three ICRC-1 ledgers". It was marked in prose and invisible
1925
1951
  /// to any gate; the glyph is what `scripts/check-update-for-read.mjs` matches.
1926
- getWalletBalances: () -> (Result_49);
1952
+ getWalletBalances: () -> (Result_50);
1927
1953
  /// Refusal reason preserved, and it is the clearest case of why a masked read is worse than no
1928
1954
  /// read: three empty strings with `configured = false` is a VALID-LOOKING answer meaning "this
1929
1955
  /// engram has no World ID configuration" — handed to a caller who merely lacks a grant. The
1930
1956
  /// fabrication is indistinguishable from the truth by construction.
1931
- getWorldIdConfig: () -> (Result_48) query;
1957
+ getWorldIdConfig: () -> (Result_49) query;
1932
1958
  /// ⟨L7⟩ UPDATE, NOT QUERY: this awaits THREE system calls — `raw_rand()` for the nonce,
1933
1959
  /// `Call.signWithEcdsa` for the signature, and `worldIdRpPublicKey()` for the derived key. A
1934
1960
  /// query can do none of them.
@@ -1937,7 +1963,7 @@ type Engram =
1937
1963
  /// Valid iff the derived signer address (getWorldIdRpSignerAddress) is registered for this rp_id in
1938
1964
  /// the World Developer Portal. Short-lived (300s TTL, idkit-server's default) and single-purpose —
1939
1965
  /// it authorizes opening one verification request, nothing else.
1940
- getWorldIdRpContext: () -> (Result_47);
1966
+ getWorldIdRpContext: () -> (Result_48);
1941
1967
  /// Owner-only: the EVM address derived from the engram's dedicated World ID RP signing key (the
1942
1968
  /// "worldid-rp" tECDSA path). Register THIS address as the rp_id's signer in the World Developer
1943
1969
  /// Portal — the engram never holds or exports a private key (only threshold shares exist, on the
@@ -1947,7 +1973,7 @@ type Engram =
1947
1973
  /// awaits `worldIdRpPublicKey()` (management `ecdsa_public_key`), and it calls `denied()` on
1948
1974
  /// refusal — a state write, which a query cannot perform. So even if the key were cached this
1949
1975
  /// could not become a query without silently retiring its denial record (ADR-0002's class).
1950
- getWorldIdRpSignerAddress: () -> (Result_44);
1976
+ getWorldIdRpSignerAddress: () -> (Result_45);
1951
1977
  /// The verified IDKitResult, verbatim, as World's /api/v4/verify accepted it — the re-checkable
1952
1978
  /// artifact behind verifiedHuman. Role-gated because it carries the NULLIFIER.
1953
1979
  /// `Result<opt Text>` — and the double wrapper is the entire point, not redundancy.
@@ -1966,7 +1992,7 @@ type Engram =
1966
1992
  /// `///`, so the dead name was PUBLISHED in engram.did and pointed every client at a method the
1967
1993
  /// canister does not serve. The tombstones below and at `about()` are historical and correct as
1968
1994
  /// written; this one was present tense, which is the difference that matters.⟩
1969
- getWorldIdVerification: () -> (Result_46) query;
1995
+ getWorldIdVerification: () -> (Result_47) query;
1970
1996
  /// ⟨0.16.0, L1⟩ THE EMERGENCY FAMILY. Every refusal below is `#Refused` or `#NotFound`, and the
1971
1997
  /// absence of a `#Conflict` here is the point: these are the calls someone makes while something
1972
1998
  /// is going wrong, and the only two answers that help are "you may not do this" and "there is
@@ -2041,7 +2067,7 @@ type Engram =
2041
2067
  ///
2042
2068
  /// Owner-gated because it reports on custody posture, and answered as a Result so that a
2043
2069
  /// wrong-identity caller gets a refusal rather than a bare `false` that reads as "no address yet".
2044
- isEvmAddressCached: () -> (Result_45) query;
2070
+ isEvmAddressCached: () -> (Result_46) query;
2045
2071
  /// Issue an OAuth authorization code. Called by an OAuth client's sign-in bridge
2046
2072
  /// (an `/auth/connector`-style route) after II authentication. The client then
2047
2073
  /// redirects the user's browser to `redirectUri` with `?code=<this>` so the
@@ -2049,7 +2075,7 @@ type Engram =
2049
2075
  ///
2050
2076
  /// Owner-only: only the engram owner can authorize a Connector install.
2051
2077
  issueAuthCode: (redirectUri: text, scope: text, codeChallenge: text,
2052
- clientId: opt text) -> (Result_44);
2078
+ clientId: opt text) -> (Result_45);
2053
2079
  /// ⟨0.16.0⟩ `getCycleSnapshotSource` DELETED — folded into `CycleSnapshot.source`, one label per
2054
2080
  /// ROW. A single label for a whole ring misattributes every row recorded under the other source,
2055
2081
  /// and the source flips by design (self-call first, balance on fallback). Its documentation of
@@ -2063,7 +2089,7 @@ type Engram =
2063
2089
  /// Refusal reason preserved, and it is the sharpest of this family: a masked `[]` reads as a
2064
2090
  /// DORMANT engram and corrupts retention math — a fabricated empty here does not just misinform a
2065
2091
  /// reader, it feeds a wrong number into a decision about destroying data.
2066
- listActivitySnapshots: (start: nat, limit: nat) -> (Result_43) query;
2092
+ listActivitySnapshots: (start: nat, limit: nat) -> (Result_44) query;
2067
2093
  /// ⟨0.16.0⟩ THE PAGE EXEMPLAR. Trap → `#Refused`, bare array → `Result<Page<T>>` (L1 + L3).
2068
2094
  ///
2069
2095
  /// The refusal prose that used to be `gatedTrap`'s `whyNotEmpty` argument is not lost — it is why
@@ -2078,7 +2104,7 @@ type Engram =
2078
2104
  ///
2079
2105
  /// `withheld` is 0: this roster is owner-only in whole, so there is no partial-visibility case.
2080
2106
  /// A method that filters rows by caller sets it — see L1's row-level honesty rule.
2081
- listAgents: (start: nat, limit: nat) -> (Result_42) query;
2107
+ listAgents: (start: nat, limit: nat) -> (Result_43) query;
2082
2108
  /// The GUARDIAN-audience projection of the agent roster — three fields, not the full record.
2083
2109
  ///
2084
2110
  /// Two audiences, two methods (L1/L8), rather than one method masking fields by caller: a
@@ -2090,7 +2116,7 @@ type Engram =
2090
2116
  /// Refusal reason preserved: `[]` reads as "this engram has no agents", and this is the list a
2091
2117
  /// guardian consults BEFORE REVOKING ONE. A fabricated empty here does not merely misinform —
2092
2118
  /// it tells someone acting under emergency powers that there is nothing to act on.
2093
- listAgentsForGuardian: (start: nat, limit: nat) -> (Result_41) query;
2119
+ listAgentsForGuardian: (start: nat, limit: nat) -> (Result_42) query;
2094
2120
  /// Owner-only: rows carry caller, amount, operation and free-text rationale. The SDK omits it.
2095
2121
  ///
2096
2122
  /// The optional leading filter SURVIVES the L3 reshape — ratified (census tier-2 #8) rather than
@@ -2123,7 +2149,21 @@ type Engram =
2123
2149
  /// For the owner and a guardian `withheld` is 0 and the page is the span. WHAT WOULD MAKE THIS
2124
2150
  /// WRONG: a reader who must see the whole record without being the owner or a guardian — the
2125
2151
  /// public certified head is the answer for integrity, and nothing else is.
2126
- listAuditEntries: (start: nat, limit: nat) -> (Result_24) query;
2152
+ ///
2153
+ /// ⟨2026-10-15, the owner's ruling 6B of 2026-10-14⟩ PUBLIC NOW, AND THE COUNT BECAME ROWS. The
2154
+ /// reply is a `Wire.RecordPage`: every entry in the span the reader may not see in full comes back
2155
+ /// as a hash-only row in `sealed` (id, SHA-256 of its body, entry hash) instead of being counted in
2156
+ /// `withheld`, so `items.size() + sealed.size()` is the span examined. Each entry is hashed first,
2157
+ /// then chained (`AuditLog`), so those rows are enough to walk from any entry to the certified
2158
+ /// head — which is what lets a stranger check one entry without the owner. A caller with no role,
2159
+ /// the anonymous caller included, is a stranger (`RecordView.readerFrom`) and gets only sealed
2160
+ /// rows; the owner and guardians still see every entry, an agent its own. Nothing here refuses,
2161
+ /// so the read's former refusal ("Anonymous caller not allowed") is gone from it.
2162
+ /// `ringFloor` says where the ring starts — a `start` below it begins at it — and `hashFirstFrom`
2163
+ /// where this record switched to the hash-first rule. A sealed row costs one SHA-256 of its body
2164
+ /// at read time; nothing new is stored. WHAT WOULD MAKE THIS WRONG: a sealed row carrying any part
2165
+ /// of a body, or a stranger reaching `items` (test/record-view.test.mo pins both).
2166
+ listAuditEntries: (start: nat, limit: nat) -> (Result_41) query;
2127
2167
  /// ⟨0.16.0, L1 + L3 — census-ruled⟩ THE TWO-MECHANISM EXCEPTION DISSOLVES.
2128
2168
  ///
2129
2169
  /// This method used to answer THREE ways to one question: a list, an `#Err` text, and a trap,
@@ -2179,13 +2219,6 @@ type Engram =
2179
2219
  /// for non-owners just as silently, and a caller could not tell a filtered tombstone list from a
2180
2220
  /// complete one. Counted before slicing, so policy-hidden rows never blur into paging.
2181
2221
  listDeletedMemoryFiles: (start: nat, limit: nat) -> (Result_36) query;
2182
- /// The registered shapes — E3: encodeTypeString is the display artifact, verbatim.
2183
- /// Stays on the engram under B1 (hybrid): EIP-712 signing is custody, and custody does not leave.
2184
- ///
2185
- /// Refusal reason preserved: `[]` reads as "this engram can sign nothing" — a claim about SIGNING
2186
- /// AUTHORITY, which is not a thing to hand an unauthorized reader. The public trail of every
2187
- /// registration remains the audit chain under getCertifiedAuditHead.
2188
- listEip712Types: (start: nat, limit: nat) -> (Result_35) query;
2189
2222
  /// Stays on the engram under B1 (hybrid): withdrawal custody does not leave.
2190
2223
  ///
2191
2224
  /// NAMED item, not a `(Text, Int)` tuple. The Int is an activation time, and a bare Int beside a
@@ -2194,7 +2227,24 @@ type Engram =
2194
2227
  /// Refusal reason preserved, and it has two halves that matter separately: `[]` reads as "this
2195
2228
  /// engram may withdraw nowhere", OR — worse — as "no allowlist is in force", which is the
2196
2229
  /// opposite security posture. It also erases any pending 24h activation from view.
2197
- listEvmWithdrawDestinations: (start: nat, limit: nat) -> (Result_34) query;
2230
+ ///
2231
+ /// ⟨2026-10-14, 4A⟩ One action's list: `typeId` names the action, and an unregistered one is
2232
+ /// `#NotFound` rather than an empty page (an empty page means "this action may sign to nothing").
2233
+ /// The item's field is `value`, not `address`: a list may hold a venue value that is no address.
2234
+ /// Readable by the owner, an active agent or an active guardian, as the old list was.
2235
+ listEip712Destinations: (typeId: blob, start: nat, limit: nat) ->
2236
+ (Result_35) query;
2237
+ /// The registered shapes — E3: encodeTypeString is the display artifact, verbatim.
2238
+ /// Stays on the engram under B1 (hybrid): EIP-712 signing is custody, and custody does not leave.
2239
+ ///
2240
+ /// Refusal reason preserved: `[]` reads as "this engram can sign nothing" — a claim about SIGNING
2241
+ /// AUTHORITY, which is not a thing to hand an unauthorized reader. The public trail of every
2242
+ /// registration remains the audit chain under getCertifiedAuditHead.
2243
+ ///
2244
+ /// ⟨2026-10-14, the owner's ruling 3A⟩ Each row carries its per-field rules (`fieldRules`), joined in
2245
+ /// from `eip712FieldRules` — they are part of what the type authorises, so a reader of the list must
2246
+ /// not have to make a second call to learn them. The row type is `Eip712TypeView`.
2247
+ listEip712Types: (start: nat, limit: nat) -> (Result_34) query;
2198
2248
  /// Accessible by owner and guardians.
2199
2249
  ///
2200
2250
  /// Refusal reason carried over from the trap, because it is the sharpest example of why this
@@ -2717,6 +2767,9 @@ type Engram =
2717
2767
  /// override is to overwrite it with a frozen copy of the global policy, which then stops
2718
2768
  /// following later changes. That makes every override permanent in effect.
2719
2769
  removeCallerSpendPolicy: (caller: principal) -> (Result_1);
2770
+ /// ⟨2026-10-14, 4A⟩ Remove a destination from one action's list. Instant, and NOT freeze-gated:
2771
+ /// removal TIGHTENS, and a frozen engram must still be able to shrink what it could sign to.
2772
+ removeEip712Destination: (typeId: blob, value: text) -> (Result_1);
2720
2773
  /// De-register a type that has NEVER SIGNED. Exists because of a hazard the first external
2721
2774
  /// validation found within hours (consumer report, 2026-08-06): a bare-name #standard registration —
2722
2775
  /// cheap, no watcher preconditions — permanently blocked the guarded namespaced registration
@@ -2726,8 +2779,9 @@ type Engram =
2726
2779
  /// removes only authority that was never exercised, which is removing nothing but the mistake.
2727
2780
  /// NOT freeze-gated, same reasoning as removeEvmWithdrawDestination: this is TIGHTENING, and a
2728
2781
  /// frozen engram must still be able to shrink what it could sign.
2782
+ /// ⟨2026-10-14⟩ `removeEvmWithdrawDestination` is now `removeEip712Destination` (ruling 4A); same
2783
+ /// reasoning. Removing a type now also drops its rules and its own destination list.
2729
2784
  removeEip712Type: (typeId: blob) -> (Result_1);
2730
- removeEvmWithdrawDestination: (dest: text) -> (Result_1);
2731
2785
  /// Owner-only: remove a guardian from the roster.
2732
2786
  ///
2733
2787
  /// Unlike revoking an agent this is NOT terminal for the principal — the guardian roster does
@@ -3136,6 +3190,10 @@ type Engram =
3136
3190
  /// bounded instead by each registered type's daily count and destination list; and agent-
3137
3191
  /// registration transactions (`signEngramRegistration`), bounded by three per caller per day and
3138
3192
  /// the 500-gwei gas ceiling. Whether the ceiling should cover them is a separate owner question.⟩
3193
+ /// ⟨2026-10-14, the owner's rulings 3A, 4A and 5A⟩ Typed-data signatures are now bounded by each
3194
+ /// registered type's daily count, its per-field rules ("at most N", "must equal X") and ITS OWN
3195
+ /// destination list, and the signing floor (`SigningFloor`) guards them as it guards x402 payments.
3196
+ /// They are still not counted against this ceiling.
3139
3197
  ///
3140
3198
  /// WHY: the owner decided on 2026-09-28 to add one daily spending ceiling across all callers on an
3141
3199
  /// engram and keep the limit of five agents. Every other spending limit is per caller, so without
@@ -3501,6 +3559,9 @@ type Engram =
3501
3559
  /// (the market cannot introduce a shape), its cool-off must have elapsed, its per-type daily cap
3502
3560
  /// still binds, the destination allowlist still fails closed, and a payments freeze still stops
3503
3561
  /// it. What the market supplies is the request; what the engram supplies is the whole policy.
3562
+ /// ⟨2026-10-14⟩ And the type's per-field rules, its own destination list (ruling 4A) and the
3563
+ /// signing floor (ruling 5A) — all in `eip712SignFor`, so they bind the market as they bind the
3564
+ /// owner; a refusal here is on the chained record under the market's caller and role.
3504
3565
  ///
3505
3566
  /// That is what "signatures only" means in code, and it is why this method needs no new authority
3506
3567
  /// model: an unregistered typeId is refused for the market exactly as it is for the owner.
@@ -3626,6 +3687,32 @@ type Eip712Value =
3626
3687
  string: text;
3627
3688
  uint: nat;
3628
3689
  };
3690
+ type Eip712TypeView =
3691
+ record {
3692
+ ackIrrevocable: bool;
3693
+ authorityClass: AuthorityClass;
3694
+ chainId: nat;
3695
+ cooloffEndsAtNs: int;
3696
+ dailySignCap: nat;
3697
+ destinationFields: vec text;
3698
+ domainName: text;
3699
+ domainSeparator: vec nat8;
3700
+ domainVersion: text;
3701
+ encodeTypeString: text;
3702
+ fieldRules: vec record {
3703
+ text;
3704
+ Eip712FieldRule;
3705
+ };
3706
+ fields: vec record {
3707
+ text;
3708
+ text;
3709
+ };
3710
+ primaryType: text;
3711
+ registeredAtNs: int;
3712
+ typeHash: vec nat8;
3713
+ typeId: blob;
3714
+ verifyingContract: text;
3715
+ };
3629
3716
  type Eip712SignatureOut =
3630
3717
  record {
3631
3718
  digest: blob;
@@ -3640,6 +3727,19 @@ type Eip712Registration =
3640
3727
  encodeTypeString: text;
3641
3728
  typeId: blob;
3642
3729
  };
3730
+ type Eip712FieldRule =
3731
+ variant {
3732
+ atMost: record {
3733
+ decimals: nat;
3734
+ max: nat;
3735
+ };
3736
+ mustEqual: text;
3737
+ };
3738
+ type Eip712Destination =
3739
+ record {
3740
+ activeFromNs: int;
3741
+ value: text;
3742
+ };
3643
3743
  type Eip3009Authorization =
3644
3744
  record {
3645
3745
  from: text;