@engramx/idl 0.16.0-rc.2 → 0.16.0-rc.21

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/registry.did CHANGED
@@ -24,6 +24,12 @@ type StandingLeaf =
24
24
  root: principal;
25
25
  version: nat;
26
26
  };
27
+ type SealedEntry =
28
+ record {
29
+ digest: blob;
30
+ entryHash: blob;
31
+ id: nat;
32
+ };
27
33
  type RowEnding =
28
34
  record {
29
35
  day: int;
@@ -57,102 +63,143 @@ type Role =
57
63
  type Result_9 =
58
64
  variant {
59
65
  Err: Error;
60
- Ok: Page_2;
66
+ Ok: EngramComputeView;
61
67
  };
62
68
  type Result_8 =
63
69
  variant {
64
70
  Err: Error;
65
- Ok: Page_1;
71
+ Ok: RestartReply;
66
72
  };
67
73
  type Result_7 =
68
74
  variant {
69
75
  Err: Error;
70
- Ok: Page;
76
+ Ok: nat;
71
77
  };
72
78
  type Result_6 =
73
79
  variant {
74
80
  Err: Error;
75
- Ok: vec text;
81
+ Ok: record {
82
+ finishByNs: int;
83
+ updateWaiting: bool;
84
+ };
76
85
  };
77
86
  type Result_5 =
78
87
  variant {
79
88
  Err: Error;
80
- Ok: CustodyMode;
89
+ Ok: record {
90
+ repaid: nat;
91
+ stillOwed: nat;
92
+ };
81
93
  };
82
94
  type Result_4 =
83
95
  variant {
84
96
  Err: Error;
85
- Ok: nat;
97
+ Ok: MeterReading;
86
98
  };
87
99
  type Result_3 =
88
100
  variant {
89
101
  Err: Error;
90
- Ok: MeterReading;
102
+ Ok: ControlStep;
91
103
  };
92
- type Result_21 =
104
+ type Result_28 =
93
105
  variant {
94
106
  Err: Error;
95
107
  Ok: FleetCycleHealth;
96
108
  };
97
- type Result_20 =
109
+ type Result_27 =
98
110
  variant {
99
111
  Err: Error;
100
112
  Ok: CertifiedStanding;
101
113
  };
114
+ type Result_26 =
115
+ variant {
116
+ Err: Error;
117
+ Ok: blob;
118
+ };
119
+ type Result_25 =
120
+ variant {
121
+ Err: Error;
122
+ Ok: PrivateMetrics;
123
+ };
124
+ type Result_24 =
125
+ variant {
126
+ Err: Error;
127
+ Ok: RestartStatus;
128
+ };
129
+ type Result_23 =
130
+ variant {
131
+ Err: Error;
132
+ Ok: OpeningCounts;
133
+ };
134
+ type Result_22 =
135
+ variant {
136
+ Err: Error;
137
+ Ok: OpenedThrough;
138
+ };
139
+ type Result_21 =
140
+ variant {
141
+ Err: Error;
142
+ Ok: ReferralCounts;
143
+ };
144
+ type Result_20 =
145
+ variant {
146
+ Err: Error;
147
+ Ok: opt text;
148
+ };
102
149
  type Result_2 =
103
150
  variant {
104
151
  Err: Error;
105
- Ok: ControlStep;
152
+ Ok: record {accepted: nat;};
106
153
  };
107
154
  type Result_19 =
108
155
  variant {
109
156
  Err: Error;
110
- Ok: OpenedThrough;
157
+ Ok: Page_6;
111
158
  };
112
159
  type Result_18 =
113
160
  variant {
114
161
  Err: Error;
115
- Ok: blob;
162
+ Ok: RecordPage;
116
163
  };
117
164
  type Result_17 =
118
165
  variant {
119
166
  Err: Error;
120
- Ok: PrivateMetrics;
167
+ Ok: Page_5;
121
168
  };
122
169
  type Result_16 =
123
170
  variant {
124
171
  Err: Error;
125
- Ok: OpeningCounts;
172
+ Ok: vec OpenedEngram;
126
173
  };
127
174
  type Result_15 =
128
175
  variant {
129
176
  Err: Error;
130
- Ok: ReferralCounts;
177
+ Ok: Page_3;
131
178
  };
132
179
  type Result_14 =
133
180
  variant {
134
181
  Err: Error;
135
- Ok: opt text;
182
+ Ok: Page_2;
136
183
  };
137
184
  type Result_13 =
138
185
  variant {
139
186
  Err: Error;
140
- Ok: Page_6;
187
+ Ok: Page_1;
141
188
  };
142
189
  type Result_12 =
143
190
  variant {
144
191
  Err: Error;
145
- Ok: Page_5;
192
+ Ok: Page;
146
193
  };
147
194
  type Result_11 =
148
195
  variant {
149
196
  Err: Error;
150
- Ok: vec OpenedEngram;
197
+ Ok: vec text;
151
198
  };
152
199
  type Result_10 =
153
200
  variant {
154
201
  Err: Error;
155
- Ok: Page_3;
202
+ Ok: CustodyMode;
156
203
  };
157
204
  type Result_1 =
158
205
  variant {
@@ -164,6 +211,31 @@ type Result =
164
211
  Err: Error;
165
212
  Ok;
166
213
  };
214
+ type RestartTotals =
215
+ record {
216
+ advanceOutstanding: nat;
217
+ advancePaid: nat;
218
+ advanceReturned: nat;
219
+ advanceWrittenOff: nat;
220
+ lent: nat;
221
+ outstanding: nat;
222
+ repaid: nat;
223
+ writtenOff: nat;
224
+ };
225
+ type RestartStatus =
226
+ record {
227
+ loanOwed: nat;
228
+ nextRestartAtNs: opt int;
229
+ openUntilNs: opt int;
230
+ };
231
+ type RestartReply =
232
+ record {
233
+ engramTold: bool;
234
+ installError: opt text;
235
+ lentCycles: nat;
236
+ securityInstalled: bool;
237
+ updateWaiting: bool;
238
+ };
167
239
  type ReserveGateConfig =
168
240
  record {
169
241
  enabled: bool;
@@ -184,6 +256,14 @@ type ReferralCounts =
184
256
  openedThroughParentLive: nat;
185
257
  throughParent: PairedSoon;
186
258
  };
259
+ type RecordPage =
260
+ record {
261
+ hashFirstFrom: nat;
262
+ items: vec AuditEntry;
263
+ ringFloor: nat;
264
+ sealed: vec SealedEntry;
265
+ total: nat;
266
+ };
187
267
  type PrivateMetrics =
188
268
  record {
189
269
  activeEngrams: nat;
@@ -352,6 +432,23 @@ type EngramRecordView =
352
432
  owner: principal;
353
433
  status: EngramStatus;
354
434
  };
435
+ type EngramComputeView =
436
+ record {
437
+ cycles: nat;
438
+ eraseAboutNs: opt int;
439
+ frozen: bool;
440
+ idlePerDay: nat;
441
+ line: nat;
442
+ quiet: bool;
443
+ restartOpenUntilNs: opt int;
444
+ runState: variant {
445
+ running;
446
+ stopped;
447
+ stopping;
448
+ };
449
+ thresholdSecs: nat;
450
+ updateWaiting: bool;
451
+ };
355
452
  type EngagementRow =
356
453
  record {
357
454
  abandonedDay: opt int;
@@ -418,6 +515,11 @@ type CertifiedStanding =
418
515
  leaf: StandingLeaf;
419
516
  witness: blob;
420
517
  };
518
+ type CertifiedBirth =
519
+ record {
520
+ certificate: opt blob;
521
+ witness: blob;
522
+ };
421
523
  type CertifiedAuditHead =
422
524
  record {
423
525
  certificate: opt blob;
@@ -469,9 +571,11 @@ type AnchorView =
469
571
  };
470
572
  type AnchorStats =
471
573
  record {
574
+ engramChainsAnchored: opt nat;
472
575
  engramsAnchored: nat;
473
576
  engramsWithConflicts: nat;
474
577
  lastAnchorAtNs: opt int;
578
+ lastEngramAnchorAtNs: opt int;
475
579
  totalAnchors: nat;
476
580
  };
477
581
  type AnchorConflict =
@@ -551,7 +655,7 @@ service : {
551
655
  /// Contrast `backupFinalize`, which does NOT verify its digest. These two look like the same
552
656
  /// protocol and are not, and the difference matters most on this one: it decides what code every
553
657
  /// engram in the fleet will run.
554
- engramWasmFinalize: (hash: text) -> (Result_4);
658
+ engramWasmFinalize: (hash: text) -> (Result_7);
555
659
  /// Chunked WASM upload — for WASMs that exceed single-call ingress limits.
556
660
  /// Flow: engramWasmInit → engramWasmPushChunk (×N) → engramWasmFinalize(hash)
557
661
  /// ⟨0.16.0 — CORRECTED 2026-08-19⟩ This line named all THREE pre-rename methods, none of which
@@ -566,7 +670,7 @@ service : {
566
670
  /// and total bytes over the cap. Neither is recoverable by pushing again — call `engramWasmInit`
567
671
  /// to clear and begin afresh. The messages say so because a caller who retries a chunk against a
568
672
  /// full buffer will retry forever.
569
- engramWasmPushChunk: (chunk: blob) -> (Result_4);
673
+ engramWasmPushChunk: (chunk: blob) -> (Result_7);
570
674
  /// Fleet cycle-health scan. Admin or metrics-viewer, PAGINATED with a hard max of 50 per page —
571
675
  /// each managed engram costs one `canister_status` await, so pages stay small to bound the
572
676
  /// message. A caller must expect to iterate.
@@ -595,7 +699,7 @@ service : {
595
699
  /// this one is a noun. That gate now reads the census's L7 citations as a second population for
596
700
  /// exactly this blind spot.⟩
597
701
  fleetCycleHealth: (offset: nat, limit: nat, thresholdCycles: nat) ->
598
- (Result_21);
702
+ (Result_28);
599
703
  /// PUBLIC: ⟨0.16.0, L2.4⟩ `fleetSummary` — the ONE public projection of this registry,
600
704
  /// replacing `status()` and ABSORBING `publicMetrics()`.
601
705
  ///
@@ -699,7 +803,7 @@ service : {
699
803
  /// is the agent's ROOT principal — the identity an owner sees as `root` on each key in their own
700
804
  /// `listAgents`. "The agent itself" is a caller holding that root key. A key for one engram has no
701
805
  /// record of its own here; asking about one gets the refusal or, from the key itself, `#NotFound`.
702
- getAgentStanding: (agent: principal) -> (Result_20) query;
806
+ getAgentStanding: (agent: principal) -> (Result_27) query;
703
807
  /// Fleet-wide anchoring liveness. Exists because ABSENCE is otherwise uninformative: an engram
704
808
  /// that never wrote, one still on a template without the push, and one whose push is broken all
705
809
  /// render as an empty getAnchors. Nothing distinguishes the first from the third, so a silently
@@ -709,6 +813,12 @@ service : {
709
813
  /// alive SOMEWHERE, which is what makes an individual engram's silence interpretable.
710
814
  ///
711
815
  /// PUBLIC: the same reader who needs the anchors needs to know whether to believe their absence.
816
+ ///
817
+ /// ⟨2026-10-11⟩ The ring also holds the TREASURY ANCHORER's chain (`getTreasuryAnchorId`), and
818
+ /// `engramsAnchored`, `totalAnchors` and `lastAnchorAtNs` count it as one more chain. The
819
+ /// engram-only pair leaves it out: `engramChainsAnchored` (always present on a registry that
820
+ /// serves it, 0 when no engram has anchored) and `lastEngramAnchorAtNs`. Read those to ask
821
+ /// whether ENGRAMS are anchoring — an active money chain must not stand in for them.
712
822
  getAnchorStats: () -> (AnchorStats) query;
713
823
  /// PUBLIC: the chain head exists to be compared, so an external monitor can detect tampering
714
824
  /// without admin access (D3). A head only whoever runs this deployment can read witnesses nothing.
@@ -746,6 +856,20 @@ service : {
746
856
  /// instead of trusting this replica, and a proof that requires a role to fetch rests on exactly
747
857
  /// the authority it was introduced to remove.
748
858
  getCertifiedAuditHead: () -> (CertifiedAuditHead) query;
859
+ /// The certified proof that a birth record's FINGERPRINT is in this registry's tree ⟨2026-10-26, the
860
+ /// owner's lineage ruling L3A⟩ — the half of an engram's birth chain the engram cannot give itself.
861
+ ///
862
+ /// PUBLIC: a proof a caller had to hold a role to fetch rests on the authority it was meant to
863
+ /// replace. It reveals only whether a fingerprint is present: the key is a salted hash (the record's
864
+ /// random secret is inside it) and the value a constant. Whoever holds the record — the engram's
865
+ /// owner, or whomever the owner showed it to — already knows the fingerprint; nobody else can ask
866
+ /// about a record they cannot guess.
867
+ ///
868
+ /// Verify as for `getCertifiedAnchor`, path ["births", <fingerprint>], leaf bytes = [0x01] (the
869
+ /// client's `verifyBirthChain` does it for a whole chain). `null` when absent, as `getCertifiedAnchor`
870
+ /// answers: there is no certified absence proof (spec question Q8). A `fingerprint` that is not 32
871
+ /// bytes is never a fingerprint, and answers `null` before the lookup.
872
+ getCertifiedBirth: (fingerprint: blob) -> (opt CertifiedBirth) query;
749
873
  /// The ATTESTABLE custody-mode fact (agent-native model item 19): "managed" | "sovereign" |
750
874
  /// "unknown", derived from the registry's OWN transition records (claimSovereignty /
751
875
  /// returnToManaged maintain sovereignEngramIds) — NOT from a canister_status probe, which needs
@@ -768,7 +892,7 @@ service : {
768
892
  ///
769
893
  /// Derived from records, never probed: a canister_status call would trap for exactly the
770
894
  /// canisters we are not the controller of, i.e. the sovereign ones this read exists to identify.
771
- getCustodyMode: (canisterId: principal) -> (Result_5) query;
895
+ getCustodyMode: (canisterId: principal) -> (Result_10) query;
772
896
  /// Cycles-health probe — slim, cycles-only shape; the money fields moved to the cashier's
773
897
  /// getCycleReserveStatus. Read by health-alert.mjs in registry mode.
774
898
  ///
@@ -798,6 +922,9 @@ service : {
798
922
  /// on two canisters is what a hand-written client cannot tell apart (a structural actor type
799
923
  /// matches either target), so it gets the rule `getMarketCanister` already follows: distinct
800
924
  /// names on distinct canisters. `…Of` says what the argument is for.
925
+ ///
926
+ /// ⟨2026-10-13⟩ The engram no longer serves `getEngramNumber` at all: its copy of the number went
927
+ /// with the genesis seed, so this is the one read of an engram's number.
801
928
  getEngramNumberOf: (canisterId: principal) -> (opt nat) query;
802
929
  /// ⟨2026-10-01, the owner's ruling of that day (2 A)⟩ What a lasting key opened through a parent:
803
930
  /// the engram, the engram it was opened from, and the cut-off's time if there is one. GATED:
@@ -806,7 +933,7 @@ service : {
806
933
  /// same words whether or not the key opened anything, so the refusal tells a stranger nothing.
807
934
  /// `#NotFound` only to a permitted reader, for a key that opened nothing: a true answer, like
808
935
  /// `listMyAgentDisputes`'s empty list.
809
- getEngramOpenedThrough: (key: principal) -> (Result_19) query;
936
+ getEngramOpenedThrough: (key: principal) -> (Result_22) query;
810
937
  /// The i-th 1 MiB slice of the attested engram wasm (0-indexed). The caller reassembles all
811
938
  /// chunks in order and MUST verify sha256(reassembled) == getEngramWasmHash before installing —
812
939
  /// the hash is the attestation; the bytes are a convenience. Out-of-range index → empty blob.
@@ -817,16 +944,27 @@ service : {
817
944
  /// its hash. A reassembler that reads `""` as end-of-stream cannot tell a finished download from
818
945
  /// a truncated one, so it would hash a partial wasm and report a mismatch against the official
819
946
  /// list, which reads as "this template is unofficial" rather than "I stopped reading too early".
820
- getEngramWasmChunk: (index: nat) -> (Result_18) query;
947
+ getEngramWasmChunk: (index: nat) -> (Result_26) query;
821
948
  /// The stored template's release class — FREE and UNGATED, because it is the checkable half of a
822
- /// promise made to people who are not our customers. Pair it with getRentStatus to verify the
823
- /// funding rule was applied: #Security funds every reachable engram; #Feature funds metered ones.
949
+ /// promise made to people who are not our customers. ⟨2026-10-25⟩ The funding rule it checks:
950
+ /// #Security — the registry pays for the install on every running engram it can reach, any size;
951
+ /// #Feature — the registry pays for no install, and each engram runs it on its own compute. (Was:
952
+ /// "pair it with getRentStatus … #Feature funds metered ones" — rent no longer enters it.)
824
953
  /// PUBLIC: ⟨0.16.0, L3⟩ The release class as a VARIANT, not a stringly-typed enum.
825
954
  ///
826
955
  /// It returned "security" or "feature" as `Text`, so every consumer compared strings and no
827
956
  /// compiler anywhere could catch a typo or a third class arriving. A variant makes the set closed
828
957
  /// and the comparison checked — and this value gates whether an upgrade is funded, so a caller
829
958
  /// that silently fails to match "security" funds nothing and reports no error.
959
+ /// ⟨CORRECTED 2026-10-26, later — the owner's restart choice 3A: "pay whenever the engram is
960
+ /// missing any security release, whatever the latest release is labelled"⟩ "#Feature — the
961
+ /// registry pays for no install" no longer holds for every engram: an engram still missing an
962
+ /// earlier security release is paid as a security update even while this reads #Feature, because
963
+ /// the current template carries that fix (UpgradeFunding.effectiveClass) — unless the current
964
+ /// template is itself behind a security release (an older build re-uploaded), which cannot deliver
965
+ /// the fix. An engram missing no security release is still never paid for a #Feature install.
966
+ /// So this value is the declared label, not the whole funding rule: the `upgrade.topUp` audit line
967
+ /// says `class=Security declared=Feature` when the two differ.
830
968
  getEngramWasmClass: () -> (ReleaseClass) query;
831
969
  /// The WASM hash of the engram template this registry will install.
832
970
  ///
@@ -848,7 +986,7 @@ service : {
848
986
  /// So L7's "the denial-logging motive for update-for-read is retired by L1" does not hold at this
849
987
  /// site. L1 retired the motive of trapping-to-refuse; it did not give queries the ability to
850
988
  /// write, which is the thing this actually depends on.
851
- getFleetMetrics: () -> (Result_17);
989
+ getFleetMetrics: () -> (Result_25);
852
990
  /// PUBLIC: a genesis note that only privileged callers could read would defeat its purpose —
853
991
  /// the reader who most needs it is the stranger deciding whether to trust this chain.
854
992
  getGenesisNote: () -> (GenesisNote) query;
@@ -903,6 +1041,16 @@ service : {
903
1041
  /// so a caller can hold a reservation with no engram. Seeing it here is what tells them to retry
904
1042
  /// provision rather than reserve again.
905
1043
  getMyReservation: () -> (opt ReservationView) query;
1044
+ /// CALLER: the app's restart sheet, for the owner (ADR-0020). What the caller's engram owes from a
1045
+ /// restart, when the next restart is allowed, and whether one is open. Refused loudly to anyone
1046
+ /// with no engram here — never "0 owed" to a caller it cannot answer for (ADR-0002).
1047
+ /// ⟨2026-10-26⟩ `openUntilNs` now reads the open restart's `finishByNs` (`restartsOpen`): when the
1048
+ /// call or the sweep will have started the engram. Shape unchanged.
1049
+ /// ⟨CORRECTED 2026-10-26, later — the owner's restart choice 2A: "apply the weekly limit only when
1050
+ /// we lend"⟩ "when the next restart is allowed" now reads "when the registry can next LEND to a
1051
+ /// restart": `nextRestartAtNs` is only the weekly limit on a loan. A restart on the owner's own
1052
+ /// compute is allowed now, whatever it says. Field name and shape unchanged.
1053
+ getMyRestartStatus: () -> (Result_24) query;
906
1054
  /// ⟨2026-10-02⟩ How many engrams were ever opened, and how — lifetime sizes of state this registry
907
1055
  /// never deletes, plus the two counters of refused openings (`Funnel.OpeningCounts` names each).
908
1056
  /// All O(1); a reader differences them day to day.
@@ -911,7 +1059,22 @@ service : {
911
1059
  /// grant). Anyone else is REFUSED by name with their class — never a zero, which would read as
912
1060
  /// "nothing was ever opened". A QUERY: counts only, and cheap; its refusal is not in the denial
913
1061
  /// log (`denied` says why a query cannot write).
914
- getOpeningCounts: () -> (Result_16) query;
1062
+ getOpeningCounts: () -> (Result_23) query;
1063
+ /// Where an engram was opened from ⟨2026-10-26, the owner's lineage ruling L4: "a child reads its own
1064
+ /// parent by its canister id"⟩: the engram, the engram it was opened from, and the cut-off's time if
1065
+ /// there is one. Closes "a handed-on child cannot read its own parent" — `getEngramOpenedThrough` is
1066
+ /// keyed by the lasting key that OPENED the engram, which a new owner does not hold.
1067
+ ///
1068
+ /// CALLER: the engram's CURRENT owner, the current owner of the engram it was opened from, or this
1069
+ /// registry's admin and audit viewers (ADR-0020). Reuses `parentOf`; no new state. The two owners are
1070
+ /// answered first; anyone else goes through the registry's combinator (`#adminOrViewer`), which
1071
+ /// refuses every other caller in the same words whether or not the id is an engram, so a refusal
1072
+ /// tells a stranger nothing. A QUERY, so the refusal is not written to the denial log (`denied`
1073
+ /// says why a query cannot write).
1074
+ /// `#NotFound` only to a permitted reader: a first engram has no parent (a true answer), and an id
1075
+ /// this registry never opened is said to be one, not passed off as a first engram (ADR-0002).
1076
+ /// L8C: `listChildrenOf` is unchanged. L7B: the change-of-owner gate is unchanged.
1077
+ getParentOf: (child: principal) -> (Result_22) query;
915
1078
  /// ⟨2026-10-02⟩ How far agents reach across owners — COUNTS ONLY: agents by how many trees their
916
1079
  /// record spans (1 · 2 · 3–4 · 5+), engrams opened through a parent that are live or cut off, and
917
1080
  /// engrams that paired an agent within seven days of opening. No principal, no row, no per-agent
@@ -923,7 +1086,7 @@ service : {
923
1086
  /// CALLERS: the admin and the audit viewers (the deployment's metrics reader holds a viewer grant),
924
1087
  /// weekly. Anyone else is REFUSED by name with their class — never zeros. A QUERY: its cost grows
925
1088
  /// with the agents and engrams it walks (one pass over each), so a reader asks weekly, not hourly.
926
- getReferralCounts: (exclude: vec principal) -> (Result_15) query;
1089
+ getReferralCounts: (exclude: vec principal) -> (Result_21) query;
927
1090
  /// PUBLIC: the biller identity is an operational fact a
928
1091
  /// payer's cashier must verify BEFORE taking money (paying into a cashier the registry does not
929
1092
  /// recognize as biller would collect funds it cannot convert into credit).
@@ -943,11 +1106,37 @@ service : {
943
1106
  /// stranger can sign up at all. An admission rule only the admitted can read is not a rule a
944
1107
  /// prospective user can act on.
945
1108
  getReserveGateConfig: () -> (ReserveGateConfig) query;
1109
+ /// PUBLIC: CALLER: the status page (ADR-0020). What the registry has lent to restart stopped engrams
1110
+ /// — lent, repaid, written off, outstanding — and what engrams gave back of the compute a paid
1111
+ /// security update advanced them (returned, written off). Ungated, because a subsidy we would not
1112
+ /// publish is one we should not spend. `getUpgradeSubsidyTotal` stays the gross figure.
1113
+ /// ⟨2026-10-26, the owner's ruling "write it off, but accounting should be exact"⟩ Two exact
1114
+ /// identities hold between any two messages: lent = repaid + writtenOff + outstanding, and
1115
+ /// advancePaid = advanceReturned + advanceWrittenOff + advanceOutstanding.
1116
+ /// ⟨2026-10-26, later — the owner's restart choice 4A: "add the release name to each write-off
1117
+ /// record. This needs no new storage."⟩ These totals are fleet-wide. PER RELEASE, read the audit
1118
+ /// chain: every line that moves an advance names the release it was paid for, `template=<module
1119
+ /// hash>` (and `version=` when the release history names one) — `upgrade.topUp` (paid, `added=`),
1120
+ /// `upgrade.advance.returned` (`returned=`, `writtenOff=`) and `upgrade.advance.writtenOff`
1121
+ /// (`writtenOff=`, including the 90-day write-off of an advance left outstanding, restart choice 5A).
1122
+ /// Summed by `template=`, they give each release's paid, returned and written-off figures exactly;
1123
+ /// what is still out per release is paid − returned − written off. Restart-loan lines are not per
1124
+ /// release (a loan pays for no release).
1125
+ /// ⟨CORRECTED 2026-10-26, later — the fix pass (the ledger review)⟩ "exactly" holds only over a
1126
+ /// COMPLETE copy of the audit chain. The registry keeps the most recent 10,000 audit entries
1127
+ /// (AuditLog's `MAX_ENTRIES`; on overflow it drops back to 9,000, oldest first), and a give-back or
1128
+ /// a 90-day write-off can land long after its `upgrade.topUp` line was dropped. A per-release sum
1129
+ /// read from the registry alone can therefore miss lines. Exact per-release figures need an archive
1130
+ /// of the chain kept from the first line on (scripts/audit-chain/monitor.mjs `--archive`); whether
1131
+ /// such an archive is kept durably is an operator's choice, not this registry's. The fleet totals
1132
+ /// this method answers are exact regardless.
1133
+ getRestartTotals: () -> (RestartTotals) query;
946
1134
  /// PUBLIC: transparency without a doxx — how many principals the deployment currently screens (0 = seam
947
1135
  /// disarmed, the shipped default). The list itself is never enumerable publicly.
948
1136
  getScreeningDenylistSize: () -> (nat) query;
949
1137
  /// How many engram template releases this registry has declared `#Security` — the class that
950
- /// skips any delay and is funded for every engram. ⟨2026-09-28, owner decision: publish the
1138
+ /// skips any delay and whose install the registry pays for on every running engram (⟨2026-10-25⟩
1139
+ /// was "is funded for every engram"). ⟨2026-09-28, owner decision: publish the
951
1140
  /// count only; the status page shows the number.⟩ It moves only when a template's class is
952
1141
  /// declared INTO `#Security` (`setEngramWasmClass`), never on `#Feature`, never down.
953
1142
  /// ⟨CORRECTED 2026-09-29⟩ It counts TEMPLATES, not declarations: each distinct template (by its
@@ -1004,9 +1193,14 @@ service : {
1004
1193
  /// `?Text` had to carry both "you may not ask" and "this engram was never funded for an upgrade"
1005
1194
  /// — and the second is a claim about OUR OWN SPEND, not an absence of one. `#Ok(null)` now means
1006
1195
  /// never funded, `#Err(#Refused)` means not your business, and no caller has to guess which.
1007
- getUpgradeFundedTemplate: (canisterId: principal) -> (Result_14) query;
1008
- /// Cumulative cycles the registry has granted to engrams for upgrades — the meter on the
1009
- /// never-gated pull path.
1196
+ getUpgradeFundedTemplate: (canisterId: principal) -> (Result_20) query;
1197
+ /// Cumulative cycles the registry has granted to engrams for upgrades — ⟨2026-10-25⟩ the meter on
1198
+ /// security-update funding: the registry pays only for security updates on running engrams (was:
1199
+ /// "the meter on the never-gated pull path"; the pull is still never refused, and a feature update
1200
+ /// it installs is not paid for).
1201
+ /// ⟨CORRECTED 2026-10-26, later — the owner's restart choice 3A⟩ "a feature update it installs is
1202
+ /// not paid for" now excepts an engram still missing an earlier security release: that install is
1203
+ /// paid as a security update and counted here (UpgradeFunding.effectiveClass).
1010
1204
  ///
1011
1205
  /// PUBLIC: a subsidy we would not publish is one we should not spend. Free and ungated.
1012
1206
  getUpgradeSubsidyTotal: () -> (nat) query;
@@ -1056,7 +1250,7 @@ service : {
1056
1250
  /// `[]` here is a SUBSTANTIVE CLAIM ABOUT ANOTHER PRINCIPAL'S FLEET — "this agent works
1057
1251
  /// nowhere" — handed to a caller who merely lacks a grant. Readable by an admin, an audit viewer,
1058
1252
  /// or that agent about itself.
1059
- listAgentEngrams: (agent: principal) -> (Result_12) query;
1253
+ listAgentEngrams: (agent: principal) -> (Result_17) query;
1060
1254
  /// Contradictory submissions, oldest-first. Empty is the normal case. Never trimmed.
1061
1255
  ///
1062
1256
  /// ⟨0.16.0, L3 — PAGED 2026-08-18⟩ This returned the WHOLE list, and the list is one an engram
@@ -1084,7 +1278,7 @@ service : {
1084
1278
  /// while keeping the evidence that two of them disagree — the fabricate-on-refusal shape aimed at
1085
1279
  /// the one reader the anchors exist for.
1086
1280
  listAnchorConflicts: (canisterId: principal, start: nat, limit: nat) ->
1087
- (Result_13) query;
1281
+ (Result_19) query;
1088
1282
  /// Witnessed heads for an engram, oldest-first. PUBLIC and ungated — an anchor a stranger cannot
1089
1283
  /// read is not an anchor (ratified: "recorded where counterparties can check them").
1090
1284
  ///
@@ -1137,7 +1331,17 @@ service : {
1137
1331
  ///
1138
1332
  /// The inline record dies for a `Page`: `earliestId` was redundant with the ring's own paging,
1139
1333
  /// and `size`/`headHash` are `getAuditHead`'s answer, published free to everyone.
1140
- listAuditEntries: (start: nat, limit: nat) -> (Result_10) query;
1334
+ ///
1335
+ /// ⟨2026-10-15, the owner's ruling 6B of 2026-10-14⟩ The reply is the shared `Wire.RecordPage`,
1336
+ /// the shape every chain canister's record read now serves, so one checker reads all of them. A
1337
+ /// viewer sees every entry, so `sealed` is always empty here; what the page adds is `ringFloor`
1338
+ /// (where the ring starts — a `start` below it begins at it) and `hashFirstFrom` (where this
1339
+ /// record switched to the hash-first rule: entries below it were hashed SHA-256(prev ‖ body)).
1340
+ /// `total` is now the head counter, as everywhere else — it was the size of the 1,000-entry window
1341
+ /// this read sliced, which is not a number about the record. The gate is unchanged: hash-only rows
1342
+ /// for strangers were ruled for the engram's record, and the status console decides a signed-in
1343
+ /// visitor's tier by whether this read refuses.
1344
+ listAuditEntries: (start: nat, limit: nat) -> (Result_18) query;
1141
1345
  /// ⟨0.16.0, L2.2⟩ RENAMED from `getMetricsViewers` — the viewer triple unifies on "audit viewer"
1142
1346
  /// across every canister, because a roster that grants audit reads should not be named after
1143
1347
  /// metrics on one canister and audit on another.
@@ -1145,7 +1349,7 @@ service : {
1145
1349
  /// MEASURED FABRICATION, kept in the record: this arm answered `(vec {})` to an ANONYMOUS caller
1146
1350
  /// on 2026-08-11 while viewers existed. An empty vec reads as "nobody holds read-only ops access"
1147
1351
  /// when the truth was "you are not on the roster".
1148
- listAuditViewers: () -> (Result_12) query;
1352
+ listAuditViewers: () -> (Result_17) query;
1149
1353
  /// PUBLIC: the release history, paged.
1150
1354
  ///
1151
1355
  /// ⟨0.16.0, L2.1⟩ A `Page`, not a bare vec. The old shape returned the WHOLE changelog on every
@@ -1163,13 +1367,13 @@ service : {
1163
1367
  ///
1164
1368
  /// Built by a pass over `parentOf` rather than from a second, reverse index: one stored fact and a
1165
1369
  /// pass bounded by the number of opened engrams, instead of two facts to keep in step.
1166
- listChildrenOf: (engram: principal) -> (Result_11) query;
1370
+ listChildrenOf: (engram: principal) -> (Result_16) query;
1167
1371
  /// ⟨0.16.0⟩ RENAMED from `readDenialLog`; the refusal becomes a value.
1168
1372
  ///
1169
1373
  /// An empty denial log reads as NOBODY HAS EVER BEEN REFUSED HERE, which is the opposite of what
1170
1374
  /// this log exists to record — so "empty" was never an acceptable answer to a caller who simply
1171
1375
  /// lacks the grant. The old trap said so; this says the same thing as data.
1172
- listDenialEntries: (start: nat, limit: nat) -> (Result_10) query;
1376
+ listDenialEntries: (start: nat, limit: nat) -> (Result_15) query;
1173
1377
  /// ⟨2026-10-02⟩ ONE ROW PER ENGAGEMENT, for the deployment's own count of use — DAYS, never
1174
1378
  /// instants, and NEVER the agent's root, enrolled key or invite.
1175
1379
  ///
@@ -1194,7 +1398,7 @@ service : {
1194
1398
  /// and a query cannot write (the reason `listEngrams` is an update). This is the most sensitive of
1195
1399
  /// the three reads — one row per engagement — so who was turned away is worth a record.
1196
1400
  listEngagementRows: (sinceDay: int, start: nat, limit: nat, companyList:
1197
- vec principal) -> (Result_9);
1401
+ vec principal) -> (Result_14);
1198
1402
  /// ⟨0.16.0, L1⟩ THE `authorized : ?Bool` FLAG IS GONE, AND SO IS EVERYTHING BUILT AROUND IT.
1199
1403
  ///
1200
1404
  /// The flag was the most carefully-argued compromise in this canister, and every word of that
@@ -1225,7 +1429,7 @@ service : {
1225
1429
  /// written and correct; what it lacked was the glyph a gate can see. Its case is the one L7's
1226
1430
  /// own text had to be corrected for — the forcing call is not a system API at all, it is
1227
1431
  /// `denied()`, a state write. See `scripts/check-update-for-read.mjs`.
1228
- listEngrams: (offset: nat, limit: nat) -> (Result_8);
1432
+ listEngrams: (offset: nat, limit: nat) -> (Result_13);
1229
1433
  /// ⟨2026-09-28, owner decision: an agent may read its own record⟩ The caller's OWN dispute
1230
1434
  /// statements, oldest first, verbatim. Keyed by `msg.caller`, so it cannot be pointed at anyone
1231
1435
  /// else, and an empty list is a true answer about the caller ("you have appended none"), never a
@@ -1272,10 +1476,10 @@ service : {
1272
1476
  /// that zero applies the SHIPPED DEFAULT — silently reversing every explicit ManualOnly consent
1273
1477
  /// choice in the fleet. That is the consequence this refusal exists to prevent, and it belongs in
1274
1478
  /// the message a caller actually receives.
1275
- listUpdatePrefs: (start: nat, limit: nat) -> (Result_7) query;
1479
+ listUpdatePrefs: (start: nat, limit: nat) -> (Result_12) query;
1276
1480
  /// Mint one-shot reserve invites (invite-issuer or admin). Codes use IC-secure randomness over a
1277
1481
  /// 32-symbol no-ambiguous alphabet (8 chars ≈ 40 bits). Batch-capped; table hard-capped.
1278
- mintReserveInvites: (count: nat) -> (Result_6);
1482
+ mintReserveInvites: (count: nat) -> (Result_11);
1279
1483
  /// The PROBED twin of `getCustodyMode`: same question, asked of the IC rather than of our
1280
1484
  /// records — hence the `probe` verb rather than a second noun.
1281
1485
  ///
@@ -1301,22 +1505,39 @@ service : {
1301
1505
  /// `ic.canister_status`. That is also the whole point of the `probe` verb — the value is read
1302
1506
  /// LIVE from the management canister rather than from a stored transition record, so a query
1303
1507
  /// could not produce it at all, not merely more cheaply.
1304
- probeCustodyMode: () -> (Result_5);
1508
+ probeCustodyMode: () -> (Result_10);
1509
+ /// What YOUR OWN engram's compute is, read by the registry — the one read that works while it is
1510
+ /// frozen.
1511
+ ///
1512
+ /// CALLER: the owner, from the app's status strip, Billing and System pages (ADR-0020).
1513
+ /// ⟨2026-10-26, the owner's ruling 1A: tell the owner, using signals that work while frozen⟩ The
1514
+ /// registry is a controller, and the network answers a controller canister's status call for a
1515
+ /// frozen engram where it refuses the owner's own (IC0207, the stopped-engram study's network read
1516
+ /// §6). UPDATE, not query: it awaits the management canister (the `probe` verb, as
1517
+ /// `probeCustodyMode`).
1518
+ /// ⟨L7⟩ ⟨marker added 2026-10-26, Finish phase; the reason above unchanged⟩ The system call that
1519
+ /// forces the update is `canister_status` on the management canister: a query cannot make an
1520
+ /// inter-canister call, so a query could not read the engram's network status at all — and that
1521
+ /// status is the only signal that still answers while the engram is frozen.
1522
+ /// No rate limit (the do-less): each call costs the registry one management
1523
+ /// call — INFERRED a few million cycles, not measured. `eraseAboutNs` is "about" and never invented:
1524
+ /// null when the network reports no idle burn.
1525
+ probeMyEngramCompute: () -> (Result_9);
1305
1526
  /// ⟨0.16.0⟩ `Ok` CARRIES THE PRINCIPAL DIRECTLY, not a one-field record wrapping it.
1306
1527
  ///
1307
1528
  /// `#Ok : { canisterId : Principal }` was a record with nothing to disambiguate: the success of a
1308
1529
  /// spawn IS the canister it produced. The wrapper cost every caller a field access to reach the
1309
1530
  /// only thing the call returns, and invited a second field later that would belong somewhere else.
1531
+ ///
1532
+ /// ⟨2026-10-13, the owner's 6A⟩ `opts.genesis` (an optional first file, written as the canister
1533
+ /// spawned) is retired: the console creates an engram with no content (decision 2 B(b),
1534
+ /// 2026-09-30), the owner kit never calls this, and only test harnesses passed one. A caller still
1535
+ /// sending the field is unaffected — Candid ignores a record field the receiver does not declare.
1310
1536
  provisionEngram: (opts:
1311
- opt
1312
- record {
1313
- genesis: opt record {
1314
- content: blob;
1315
- path: text;
1316
- };
1317
- invite: opt text;
1318
- walletProof: opt blob;
1319
- }) -> (Result_1);
1537
+ opt record {
1538
+ invite: opt text;
1539
+ walletProof: opt blob;
1540
+ }) -> (Result_1);
1320
1541
  removeAuditViewer: (viewer: principal) -> (Result);
1321
1542
  /// ⟨0.16.0⟩ `Ok` IS THE ANSWER — the `{ reserved : Bool }` wrapper is gone.
1322
1543
  ///
@@ -1328,6 +1549,66 @@ service : {
1328
1549
  invite: opt text;
1329
1550
  walletProof: opt blob;
1330
1551
  }) -> (Result);
1552
+ /// Admin (the wasm admin): give one grown engram's working memory back, in place. The engram's
1553
+ /// stable graph is copied into its stable memory and the SAME module is reinstalled with
1554
+ /// `wasm_memory_persistence = ?#replace`, so the engram restarts in a fresh, small wasm memory with
1555
+ /// every file, version, record entry, setting and key it had (MemoryReset.mo).
1556
+ ///
1557
+ /// REFUSES, and changes nothing, when: the caller is not the wasm admin; the registry does not know
1558
+ /// the engram; a change of owner or a restart is open; its status cannot be read (a sovereign engram);
1559
+ /// it is not running; it is not on the current template; its wasm memory is under
1560
+ /// `MemoryReset.WASM_FLOOR_BYTES` (nothing to give back — and so a second reset straight after a
1561
+ /// first); its balance is short of the install hold above its own freezing line (no dip, no deposit);
1562
+ /// or one of its own calls is in flight ("Busy, try again").
1563
+ ///
1564
+ /// WHO PAYS: the engram, as for any install — `install_code` is charged to the canister it installs
1565
+ /// on, and the stabilise / rebuild steps are the engram's own messages. The registry deposits
1566
+ /// nothing; it pays only for its own calls. Two installs run: an ordinary one of the same module
1567
+ /// first, which is the network's test for a call in flight while nothing is yet at stake, then the
1568
+ /// replace.
1569
+ ///
1570
+ /// ONCE STARTED it finishes or says the engram is HELD: between the stabilise call and the replace
1571
+ /// install the engram refuses every message, so a failure there answers `#Unavailable` naming the
1572
+ /// step, and running this method again picks up where it stopped (it reads the held state from the
1573
+ /// engram itself). Do not publish a new template while a reset is held.
1574
+ ///
1575
+ /// Never run on production engrams (the owner's ruling). On the staging network, as the wasm admin,
1576
+ /// with the engram's canister id in ENGRAM:
1577
+ /// icp canister call registry-staging resetEngramMemory "(principal \"$ENGRAM\")" -e ic
1578
+ resetEngramMemory: (canisterId: principal) -> (Result);
1579
+ /// Restart YOUR OWN stopped engram.
1580
+ ///
1581
+ /// CALLER: the owner, from the app's restart sheet (ADR-0020). Afterwards the app runs the engram's
1582
+ /// own `convertEarningsToCycles` as the owner, which pays any loan back FIRST.
1583
+ ///
1584
+ /// ⟨REWRITTEN 2026-10-26, the owner's ruling 2A of that day⟩ What it does, in this order: stops the
1585
+ /// engram; adds compute — the owner's own (already added through `stopMyEngramForRestart` and a
1586
+ /// top-up from their account), or a loan of what it still lacks to run at its OWN setting (at most
1587
+ /// 0.25T, only after the biller confirms the wallet holds enough to repay it); installs the waiting
1588
+ /// security release if the engram is behind one and the owner allows automatic updates (paid as a
1589
+ /// security update — we pay because we do not want security incidents); puts the owner's freezing
1590
+ /// setting back; and only then starts it. It never lowers the setting on a running engram. A step
1591
+ /// that fails never leaves the engram stopped: the registry's sweep finishes it within minutes.
1592
+ ///
1593
+ /// Refused BEFORE anything is stopped, saying why: not your engram; sovereign; a change of owner
1594
+ /// unfinished; restarted in the last 7 days; a loan still owed; an update installing; a restart
1595
+ /// already running; code the registry never published; running (nothing to restart); needing more
1596
+ /// than one loan; a waiting security update that this restart could not cover (it would start old
1597
+ /// code); an engram opened through another engram that would need a loan; the fleet-wide ceiling;
1598
+ /// no biller, or a wallet too low to repay. A restart that lent nothing does not spend the week.
1599
+ /// ⟨CORRECTED 2026-10-26, later — the owner's restart choices 1A and 2A of that day⟩ The list above is
1600
+ /// the record of the build before them. Now: "restarted in the last 7 days" and "a loan still owed"
1601
+ /// refuse ONLY a restart that would LEND (2A: "apply the weekly limit only when we lend") — asked
1602
+ /// once the plan knows the loan, and again after every await before the loan is made
1603
+ /// (`RestartLoan.lendGate`); a restart on the owner's own compute is never refused by them and never
1604
+ /// spends the week, which is taken only in the step that records a loan. "An engram opened through
1605
+ /// another engram that would need a loan" is GONE (1A: "lend to children like any other engram") —
1606
+ /// such an engram is lent to under the same ceiling, wallet check and repay-first as any other: the
1607
+ /// biller reads the engram's OWN wallet by its own id, and the engram's own Convert repays. New: a
1608
+ /// second call while one is still running for the same engram (`restartCallsRunning`), which is
1609
+ /// what now keeps two interleaved calls from both lending or both stopping and starting — the week
1610
+ /// used to double as that guard.
1611
+ restartMyStoppedEngram: () -> (Result_8);
1331
1612
  /// Return to managed: user calls AFTER adding registry back as controller
1332
1613
  returnToManaged: () -> (Result);
1333
1614
  /// Set admin. Authority decision lives in the pure Auth module (unit-tested); this func keeps only
@@ -1379,7 +1660,7 @@ service : {
1379
1660
  /// Flip the reserve gate (admin-only; audit-logged). OFF restores fully-open admission.
1380
1661
  setReserveGateEnabled: (enabled: bool) -> (Result);
1381
1662
  setScreeningDenylist: (list: vec principal) -> (Result);
1382
- setSpawnCeiling: (n: nat) -> (Result_4);
1663
+ setSpawnCeiling: (n: nat) -> (Result_7);
1383
1664
  setTreasuryAnchorId: (p: opt principal) -> (Result);
1384
1665
  /// Set the wallet-canister allowlist for the wallet-rooted exemption (admin-only). Small by
1385
1666
  /// design — these are identity ISSUERS (e.g. Internet Identity), not users.
@@ -1395,9 +1676,19 @@ service : {
1395
1676
  /// bypasses the funding constraint.
1396
1677
  /// Admin dial for the upgrade top-up floor (0 = disabled). Capped at one endowment so the dial
1397
1678
  /// itself cannot turn upgrades into an unbounded drain.
1398
- setUpgradeTopUpFloor: (n: nat) -> (Result_4);
1679
+ setUpgradeTopUpFloor: (n: nat) -> (Result_7);
1399
1680
  /// Root admin assigns the role key (pass null to clear, reverting the role to the root admin).
1400
1681
  setWasmAdmin: (p: opt principal) -> (Result);
1682
+ /// Stop YOUR OWN stopped-or-starving engram so you can add compute from your account and restart it.
1683
+ ///
1684
+ /// CALLER: the owner, from the app's "Add compute from my account" when the engram has stopped and a
1685
+ /// security update is waiting (ADR-0020). ⟨2026-10-26, the owner's ruling 2A⟩ Stops the engram so
1686
+ /// that compute the owner adds next cannot wake its old code; the owner then adds compute through
1687
+ /// the biller's own top-up and calls `restartMyStoppedEngram`, which installs the waiting update and
1688
+ /// starts it. If the owner walks away, the sweep finishes it after 30 minutes: install if covered,
1689
+ /// restore, start. Never left stopped. It lends nothing, so it takes no week; it refuses an engram
1690
+ /// that is not stuck, so a healthy engram is never taken offline (spec question Q15).
1691
+ stopMyEngramForRestart: () -> (Result_6);
1401
1692
  /// An engram witnesses its own audit head. Callable ONLY by a registered engram — msg.caller is
1402
1693
  /// the engram principal, so attribution needs no signature and cannot be forged by a third party.
1403
1694
  ///
@@ -1419,6 +1710,15 @@ service : {
1419
1710
  /// The market already calls it under this name, which is how the rename got its urgency: a
1420
1711
  /// hand-written client IDL type-checks against a method that does not exist.
1421
1712
  sysAnchorHead: (head: blob, total: nat) -> (Result);
1713
+ /// CALLER: an engram, from inside its owner's `convertEarningsToCycles`, once the conversion landed
1714
+ /// (ADR-0020). Attach up to what is owed: the registry accepts no more than the outstanding loan
1715
+ /// (the network returns the rest) and records it. `#NotFound` when nothing is owed (the loan was
1716
+ /// written off, or repaid): the engram then clears its own record.
1717
+ /// ⟨CHANGED 2026-10-26, the owner's ruling 2A⟩ REPAY-ONLY. It no longer puts a freezing setting back
1718
+ /// (the restart restores it before the start) and no longer queues a security push (the restart
1719
+ /// installs it before the start; the wake watcher covers other wakes). The name and reply are
1720
+ /// unchanged, so the engram's hand client still matches.
1721
+ sysCloseRestart: () -> (Result_5);
1422
1722
  /// ⟨2026-09-29, review PR-3: a half-finished change of owner⟩ A SOVEREIGN engram reports that it
1423
1723
  /// moved control of its code to `newOwner`, which ends the change of owner this registry marked
1424
1724
  /// when it moved its record (`ControlHandover.Pending`). Until this arrives the registry refuses the
@@ -1437,7 +1737,7 @@ service : {
1437
1737
  /// Single-engram metering probe — the push-on-payment sizing read. Biller-gated and
1438
1738
  /// cycles-attached like the sweep; same row semantics, one engram, no heartbeat stamp
1439
1739
  /// (a single probe is not a completed round).
1440
- sysMeterEngram: (canisterId: principal) -> (Result_3);
1740
+ sysMeterEngram: (canisterId: principal) -> (Result_4);
1441
1741
  /// ⟨2026-10-02⟩ An engram tells this registry that its owner reset it.
1442
1742
  ///
1443
1743
  /// CALLER: a registered engram, about itself — `canisterToOwner` membership, checked first
@@ -1494,7 +1794,7 @@ service : {
1494
1794
  /// moved record and is refused. A report of the owner the registry already records is a RETRY of
1495
1795
  /// a transfer the engram did not finish, and moves control again (that is the way out `stuck`
1496
1796
  /// names). The rules are in `src/shared/ControlHandover.mo`.
1497
- sysNotifyOwnershipTransfer: (newOwner: principal) -> (Result_2);
1797
+ sysNotifyOwnershipTransfer: (newOwner: principal) -> (Result_3);
1498
1798
  /// ⟨2026-09-28, owner decision: build the full agent track-record design for the launch release⟩
1499
1799
  /// An engram tells this registry that one of its agents started, or ended and WHY.
1500
1800
  ///
@@ -1556,6 +1856,41 @@ service : {
1556
1856
  event: EdgeEvent;
1557
1857
  root: principal;
1558
1858
  }) -> (Result);
1859
+ /// CALLER: an engram, from inside its `sysReturnUpgradeAdvance` (ADR-0020). Attach what is being
1860
+ /// given back of the compute a paid security update advanced it. The registry accepts no more than
1861
+ /// the outstanding advance (the network returns the rest) and writes off whatever was not returned
1862
+ /// — what the install used and what the engram had to keep — never carried as a debt.
1863
+ /// ⟨2026-10-26, the owner's ruling "accounting should be exact"⟩ The write-off here is the exact
1864
+ /// figure advance − accepted, from the ledger entry and the cycles actually accepted, and the audit
1865
+ /// line carries advance, returned and writtenOff.
1866
+ /// ⟨2026-10-26, later — the owner's restart choices 4A and 5A⟩ The engram may have more than one
1867
+ /// advance out (one per release paid; RestartLoan.repayAdvances): the cycles are accepted up to their
1868
+ /// sum and settled OLDEST FIRST, and each advance gets its own audit line naming the release it was
1869
+ /// paid for (`template=`), with its own returned and written-off parts — the lines sum exactly to
1870
+ /// `accepted` and to the write-off. AN ADVANCE ALREADY WRITTEN OFF (the 90-day sweep) IS NOT ON THE
1871
+ /// LEDGER, so nothing sent for it is accepted — the network returns those cycles to the engram — and
1872
+ /// `advanceReturned` never counts a written-off cycle: no double count. When nothing at all is out,
1873
+ /// the reply is `#NotFound` and nothing is accepted (as before).
1874
+ /// ⟨CORRECTED 2026-10-26, later — the fix pass on 4A⟩ NEWEST first, not oldest first: the engram can
1875
+ /// give back only what it holds above its balance before the latest deposit, so the cycles are the
1876
+ /// newest advance's (RestartLoan.repayAdvances says why, and when that reading is wrong).
1877
+ /// ⟨CHANGED 2026-10-26, the owner's review choice 1B: "take back only what we added; anything left
1878
+ /// over goes to the 90-day write-off"⟩ The engram now names THE ADVANCE it is giving back
1879
+ /// (`advanceId`, which the registry handed it in `sysReturnUpgradeAdvance` — the one this install's
1880
+ /// deposit put on the ledger). The registry accepts AT MOST THAT ADVANCE'S AMOUNT, settles THAT
1881
+ /// entry alone (returned + written off = its amount, one `upgrade.advance.returned` line naming its
1882
+ /// release and id) and leaves every other advance of the engram on the ledger, for its own
1883
+ /// give-back or the 90-day write-off. The paragraphs above about "the sum", "settled OLDEST FIRST"
1884
+ /// and "NEWEST first" describe the shape this replaces. An id that is not on the ledger for this
1885
+ /// caller (already settled, written off after 90 days, or never its own) accepts nothing — the
1886
+ /// network returns the attached cycles to the engram — and answers `#NotFound`; when a recorded
1887
+ /// engram attached cycles, an `upgrade.advance.notOut` line in the registry's unchained refusal log
1888
+ /// says so (never the chained audit log: it moves nothing, and any engram can send it). Nothing is
1889
+ /// ever counted twice.
1890
+ /// WHAT WOULD MAKE THIS WRONG: an engram naming an id other than the one it was handed — it can only
1891
+ /// name one of its OWN advances (the caller must match), so the worst it can do is settle its own
1892
+ /// other advance early with cycles that are still the registry's.
1893
+ sysRepayUpgradeAdvance: (a: record {advanceId: nat;}) -> (Result_2);
1559
1894
  /// ⟨2026-09-29, owner ruling follow-up 8⟩ A SOVEREIGN engram could not change its own controllers
1560
1895
  /// after this registry moved its record, and asks for the record back so the transfer does not
1561
1896
  /// complete. Gated like `sysNotifyOwnershipTransfer` (the caller must BE the engram), and only for
@@ -1615,31 +1950,41 @@ service : {
1615
1950
  /// Admin: upgrade one engram to the current template. RESPECTS the owner's update preference —
1616
1951
  /// an engram set to `#ManualOnly` is not moved by this method, which is what makes the preference
1617
1952
  /// meaningful rather than advisory. The owner's own `upgradeMyEngram` is unaffected either way.
1953
+ ///
1954
+ /// ⟨2026-10-25, the owner's ruling of that day⟩ Same funding decision and dip as the owner's pull:
1955
+ /// paid only for a #Security update on a running engram. A push is the registry's own initiative,
1956
+ /// so where the engram cannot hold the install even with its setting lowered, the push is SKIPPED
1957
+ /// with `#Conflict` and not attempted — the owner can still pull it, and the pull is never refused.
1618
1958
  upgradeEngram: (canisterId: principal) -> (Result);
1619
1959
  /// Upgrade YOUR OWN engram to the registry's current template. Self-service — no admin, no
1620
1960
  /// queue, no approval.
1621
1961
  ///
1622
- /// ⚠ THE PULL IS ALWAYS FUNDED, regardless of release class or rent state, and that is a
1623
- /// commitment rather than an implementation detail: `install_code` needs the balance to cover the
1624
- /// install ABOVE the freezing threshold, so the registry lifts the engram over that bar if cycles
1625
- /// are what is stopping it. Refusing an owner their own fix for nonpayment is the ransom the
1626
- /// continuity-rent model forbids, and withholding a security fix would be worse than anything
1627
- /// that model gates. The lift is best-effort: if it fails, the install still runs and returns the
1628
- /// REAL error, so a top-up problem can never masquerade as an upgrade problem or hide one.
1629
- /// ⟨2026-09-28, owner decision: the registry only pays for upgrades of engrams running our
1630
- /// published code⟩ One exception to "always funded": an engram whose installed module is not one
1631
- /// this registry published is not lifted (`fundUpgradeIfNeeded`, audit
1632
- /// `upgrade.topUp.unpublishedCode`). The install is still attempted — the owner is never refused
1633
- /// their fix, only our cycles for it.
1634
- /// ⟨2026-09-29⟩ And when that install then FAILS, the reply says why the registry did not pay and
1635
- /// what the owner can do (`TemplatePolicy.unfundedUpgradeFailure`) — before, the refusal was only
1636
- /// in the registry's own log and the owner saw a bare out-of-cycles error. Same reply type.
1637
- /// ⟨2026-10-01, the owner's ruling of that day (2 A)⟩ A second exception beside the first: an
1638
- /// engram opened through a parent (`parentOf`, written by `sysSpawnChild`) is funded by the
1639
- /// registry never — not at birth, not at an upgrade (`fundUpgradeIfNeeded`, audit
1640
- /// `upgrade.topUp.childEngram`). The install is still attempted; the owner is never refused their
1641
- /// fix, only our cycles for it, and a failed install says so
1642
- /// (`TemplatePolicy.childUnfundedUpgradeFailure`).
1962
+ /// ⟨2026-10-25, the owner's ruling of that day⟩ THE INSTALL IS ALWAYS ATTEMPTED. Refusing an owner
1963
+ /// their own update for nonpayment is the ransom the continuity model forbids, so this method never
1964
+ /// refuses for compute or payment. What the registry PAYS for is narrower: a #Security update on a
1965
+ /// running engram, any size — paid because we do not want security incidents (the owner,
1966
+ /// 2026-10-25). A #Feature update runs on the engram's own compute. Four standing exclusions are
1967
+ /// never paid for: an engram that has stopped (below its running line — it runs nothing, so its old
1968
+ /// code is not exposed while stopped), one opened through a parent (the ruling of 2026-10-01), one
1969
+ /// running a module the registry never published (2026-09-28), and a second deposit for the same
1970
+ /// release.
1971
+ /// ⟨CORRECTED 2026-10-26, the owner's rulings of that day⟩ THREE standing exclusions: an engram
1972
+ /// opened through a parent is now paid for a security update like any other ("including child
1973
+ /// engrams, but not including engrams running unofficial code"), and a #Feature update is never
1974
+ /// paid, rent or no rent ("where rent is paid, feature upgrades are paid by the engram").
1975
+ /// ⟨CORRECTED 2026-10-26, later — the owner's restart choice 3A: "pay whenever the engram is
1976
+ /// missing any security release, whatever the latest release is labelled"⟩ "a #Feature update is
1977
+ /// never paid" now excepts an engram still missing an earlier security release: its install of a
1978
+ /// #Feature template is paid as a security update, because the template carries that fix
1979
+ /// (UpgradeFunding.effectiveClass) — unless the template is itself behind a security release.
1980
+ /// When it helps, the registry lowers the engram's freezing setting to one hour for the
1981
+ /// install and puts the owner's value back after (the dip), so an install needs only ~0.32T above
1982
+ /// an hour's burn rather than the hold above the whole 30-day line.
1983
+ ///
1984
+ /// When the install FAILS after the registry declined to pay, the reply says why and what to do
1985
+ /// (UpgradeFunding.pullFailure): `#Conflict` when the engram needs more compute (the owner's
1986
+ /// action — add compute), `#Unavailable` when the registry could not pay this time (retryable).
1987
+ /// A failure after a paid or unneeded deposit answers `#Unavailable` with the network's reply.
1643
1988
  ///
1644
1989
  /// An engram already on the current template is a silent no-op. A SOVEREIGN engram gets
1645
1990
  /// "registry is no longer a controller" — accurate, because it is no longer ours to install on.