@substrat-run/kernel 0.141.0 → 0.143.0

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.
Files changed (195) hide show
  1. package/dist/async-invocation-log.d.ts +1 -1
  2. package/dist/async-invocation-log.d.ts.map +1 -1
  3. package/dist/async-invocation-log.js +1 -1
  4. package/dist/async-invocation-log.js.map +1 -1
  5. package/dist/attachment-extractor.d.ts +0 -9
  6. package/dist/attachment-extractor.d.ts.map +1 -1
  7. package/dist/attachment-extractor.js +2 -2
  8. package/dist/attachment-extractor.js.map +1 -1
  9. package/dist/attachment-text.d.ts +0 -5
  10. package/dist/attachment-text.d.ts.map +1 -1
  11. package/dist/attachment-text.js +0 -4
  12. package/dist/attachment-text.js.map +1 -1
  13. package/dist/attribution.d.ts +0 -7
  14. package/dist/attribution.d.ts.map +1 -1
  15. package/dist/attribution.js +0 -7
  16. package/dist/attribution.js.map +1 -1
  17. package/dist/audit-outcome.d.ts +60 -2
  18. package/dist/audit-outcome.d.ts.map +1 -1
  19. package/dist/audit-outcome.js +63 -3
  20. package/dist/audit-outcome.js.map +1 -1
  21. package/dist/capability.d.ts +123 -14
  22. package/dist/capability.d.ts.map +1 -1
  23. package/dist/capability.js +266 -16
  24. package/dist/capability.js.map +1 -1
  25. package/dist/connector-calls.d.ts +3 -77
  26. package/dist/connector-calls.d.ts.map +1 -1
  27. package/dist/connector-calls.js +4 -63
  28. package/dist/connector-calls.js.map +1 -1
  29. package/dist/denial-query.d.ts +0 -14
  30. package/dist/denial-query.d.ts.map +1 -1
  31. package/dist/denial-query.js +1 -1
  32. package/dist/denial-query.js.map +1 -1
  33. package/dist/derived-handlers.d.ts +17 -0
  34. package/dist/derived-handlers.d.ts.map +1 -0
  35. package/dist/derived-handlers.js +106 -0
  36. package/dist/derived-handlers.js.map +1 -0
  37. package/dist/entity-grant-shape.d.ts +79 -7
  38. package/dist/entity-grant-shape.d.ts.map +1 -1
  39. package/dist/entity-grant-shape.js +177 -74
  40. package/dist/entity-grant-shape.js.map +1 -1
  41. package/dist/entity-grant.d.ts +0 -5
  42. package/dist/entity-grant.d.ts.map +1 -1
  43. package/dist/entity-grant.js +0 -4
  44. package/dist/entity-grant.js.map +1 -1
  45. package/dist/entity-state.d.ts +0 -17
  46. package/dist/entity-state.d.ts.map +1 -1
  47. package/dist/entity-state.js +2 -2
  48. package/dist/entity-state.js.map +1 -1
  49. package/dist/entity-trash.d.ts +2 -2
  50. package/dist/entity-trash.d.ts.map +1 -1
  51. package/dist/entity-trash.js +6 -6
  52. package/dist/entity-trash.js.map +1 -1
  53. package/dist/grant-scoped-read.d.ts +0 -2
  54. package/dist/grant-scoped-read.d.ts.map +1 -1
  55. package/dist/grant-scoped-read.js +2 -2
  56. package/dist/grant-scoped-read.js.map +1 -1
  57. package/dist/index.d.ts +58 -139
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +53 -107
  60. package/dist/index.js.map +1 -1
  61. package/dist/invocation-line.d.ts +211 -0
  62. package/dist/invocation-line.d.ts.map +1 -0
  63. package/dist/invocation-line.js +33 -0
  64. package/dist/invocation-line.js.map +1 -0
  65. package/dist/job-run.d.ts +0 -39
  66. package/dist/job-run.d.ts.map +1 -1
  67. package/dist/job-run.js +6 -6
  68. package/dist/job-run.js.map +1 -1
  69. package/dist/list-index.d.ts +0 -45
  70. package/dist/list-index.d.ts.map +1 -1
  71. package/dist/list-index.js +2 -39
  72. package/dist/list-index.js.map +1 -1
  73. package/dist/membership-executor.d.ts +2 -1
  74. package/dist/membership-executor.d.ts.map +1 -1
  75. package/dist/membership-executor.js +1 -1
  76. package/dist/membership-executor.js.map +1 -1
  77. package/dist/meters.d.ts +21 -1
  78. package/dist/meters.d.ts.map +1 -1
  79. package/dist/meters.js +0 -0
  80. package/dist/meters.js.map +1 -1
  81. package/dist/migration-digest.d.ts +0 -12
  82. package/dist/migration-digest.d.ts.map +1 -1
  83. package/dist/migration-digest.js +1 -1
  84. package/dist/migration-digest.js.map +1 -1
  85. package/dist/module-log.d.ts +5 -4
  86. package/dist/module-log.d.ts.map +1 -1
  87. package/dist/module-log.js +5 -4
  88. package/dist/module-log.js.map +1 -1
  89. package/dist/module-operations.d.ts +146 -0
  90. package/dist/module-operations.d.ts.map +1 -0
  91. package/dist/module-operations.js +174 -0
  92. package/dist/module-operations.js.map +1 -0
  93. package/dist/peer.d.ts +0 -2
  94. package/dist/peer.d.ts.map +1 -1
  95. package/dist/peer.js +0 -4
  96. package/dist/peer.js.map +1 -1
  97. package/dist/permission-checker.d.ts +23 -0
  98. package/dist/permission-checker.d.ts.map +1 -1
  99. package/dist/permission-checker.js.map +1 -1
  100. package/dist/permission-eval.d.ts.map +1 -1
  101. package/dist/permission-eval.js +77 -21
  102. package/dist/permission-eval.js.map +1 -1
  103. package/dist/platform-request-query.d.ts +6 -6
  104. package/dist/platform-request-query.d.ts.map +1 -1
  105. package/dist/platform-request-query.js +23 -7
  106. package/dist/platform-request-query.js.map +1 -1
  107. package/dist/platform-sweep.d.ts +107 -3
  108. package/dist/platform-sweep.d.ts.map +1 -1
  109. package/dist/platform-sweep.js +131 -2
  110. package/dist/platform-sweep.js.map +1 -1
  111. package/dist/refusal-query.d.ts +0 -11
  112. package/dist/refusal-query.d.ts.map +1 -1
  113. package/dist/refusal-query.js +1 -1
  114. package/dist/refusal-query.js.map +1 -1
  115. package/dist/refusals.d.ts +1 -3
  116. package/dist/refusals.d.ts.map +1 -1
  117. package/dist/refusals.js +0 -2
  118. package/dist/refusals.js.map +1 -1
  119. package/dist/row-decode.d.ts +16 -1
  120. package/dist/row-decode.d.ts.map +1 -1
  121. package/dist/row-decode.js +18 -6
  122. package/dist/row-decode.js.map +1 -1
  123. package/dist/scope-copy-ledger.d.ts +49 -2
  124. package/dist/scope-copy-ledger.d.ts.map +1 -1
  125. package/dist/scope-copy-ledger.js +44 -1
  126. package/dist/scope-copy-ledger.js.map +1 -1
  127. package/dist/scope-host.d.ts +100 -110
  128. package/dist/scope-host.d.ts.map +1 -1
  129. package/dist/scope-host.js +0 -17
  130. package/dist/scope-host.js.map +1 -1
  131. package/dist/scope-lifecycle.d.ts +0 -21
  132. package/dist/scope-lifecycle.d.ts.map +1 -1
  133. package/dist/scope-lifecycle.js +1 -1
  134. package/dist/scope-lifecycle.js.map +1 -1
  135. package/dist/scope-role-admin.d.ts +0 -6
  136. package/dist/scope-role-admin.d.ts.map +1 -1
  137. package/dist/scope-role-admin.js +1 -1
  138. package/dist/scope-role-admin.js.map +1 -1
  139. package/dist/search-index.d.ts +0 -23
  140. package/dist/search-index.d.ts.map +1 -1
  141. package/dist/search-index.js +2 -24
  142. package/dist/search-index.js.map +1 -1
  143. package/dist/spine-restore.d.ts +0 -22
  144. package/dist/spine-restore.d.ts.map +1 -1
  145. package/dist/spine-restore.js +2 -2
  146. package/dist/spine-restore.js.map +1 -1
  147. package/dist/sql-limits.d.ts +4 -0
  148. package/dist/sql-limits.d.ts.map +1 -1
  149. package/dist/sql-limits.js +4 -0
  150. package/dist/sql-limits.js.map +1 -1
  151. package/dist/storage-gauge.d.ts +125 -0
  152. package/dist/storage-gauge.d.ts.map +1 -0
  153. package/dist/storage-gauge.js +234 -0
  154. package/dist/storage-gauge.js.map +1 -0
  155. package/dist/subject-redaction.d.ts +0 -38
  156. package/dist/subject-redaction.d.ts.map +1 -1
  157. package/dist/subject-redaction.js +4 -4
  158. package/dist/subject-redaction.js.map +1 -1
  159. package/dist/system-switch-record.d.ts +0 -4
  160. package/dist/system-switch-record.d.ts.map +1 -1
  161. package/dist/system-switch-record.js +2 -2
  162. package/dist/system-switch-record.js.map +1 -1
  163. package/dist/system-switch.d.ts +0 -23
  164. package/dist/system-switch.d.ts.map +1 -1
  165. package/dist/system-switch.js +1 -1
  166. package/dist/system-switch.js.map +1 -1
  167. package/dist/table-ownership.d.ts +0 -32
  168. package/dist/table-ownership.d.ts.map +1 -1
  169. package/dist/table-ownership.js +5 -5
  170. package/dist/table-ownership.js.map +1 -1
  171. package/dist/testing.d.ts +17 -0
  172. package/dist/testing.d.ts.map +1 -0
  173. package/dist/testing.js +15 -0
  174. package/dist/testing.js.map +1 -0
  175. package/dist/vertical-events.d.ts +1 -7
  176. package/dist/vertical-events.d.ts.map +1 -1
  177. package/dist/vertical-events.js +2 -10
  178. package/dist/vertical-events.js.map +1 -1
  179. package/package.json +14 -2
  180. package/dist/invocation-log.d.ts +0 -447
  181. package/dist/invocation-log.d.ts.map +0 -1
  182. package/dist/invocation-log.js +0 -410
  183. package/dist/invocation-log.js.map +0 -1
  184. package/dist/platform-call.d.ts +0 -45
  185. package/dist/platform-call.d.ts.map +0 -1
  186. package/dist/platform-call.js +0 -63
  187. package/dist/platform-call.js.map +0 -1
  188. package/dist/provider-error.d.ts +0 -38
  189. package/dist/provider-error.d.ts.map +0 -1
  190. package/dist/provider-error.js +0 -65
  191. package/dist/provider-error.js.map +0 -1
  192. package/dist/routed-node.d.ts +0 -87
  193. package/dist/routed-node.d.ts.map +0 -1
  194. package/dist/routed-node.js +0 -67
  195. package/dist/routed-node.js.map +0 -1
@@ -19,7 +19,8 @@ import { type Actor, type PermissionKey } from '@substrat-run/contracts';
19
19
  * - a REQUIRED scalar has no honest empty value, so a row that breaks one cannot be the
20
20
  * contract shape without lying. It is collected, and `finish` throws naming every
21
21
  * column the row broke — the strict decode this replaced, kept for exactly the part it
22
- * cannot honestly relax.
22
+ * cannot honestly relax. A read whose contract has a variant for such a row (the intent
23
+ * journal's, #1637) uses `finishOr` and returns that instead.
23
24
  *
24
25
  * **Every value a decoder built on this returns satisfies the published schema**, which
25
26
  * is #1634's review finding carried forward: a field is only ever replaced by a value its
@@ -66,6 +67,12 @@ export declare const UNDECODED_ACTOR: Actor;
66
67
  * `decodeError`, beside this self-naming marker.
67
68
  */
68
69
  export declare const UNDECODED_PERMISSION: PermissionKey;
70
+ /**
71
+ * Stored text cut to {@link QUOTED_MAX}, with `…` where it was cut — for any decoder that hands a
72
+ * stored value back verbatim (#1637), so an oversized one cannot ride into a report, a log line
73
+ * that repeats every tick, or a screen.
74
+ */
75
+ export declare function capped(text: string): string;
69
76
  /** `column: message`, for the first issue a field's schema raised. */
70
77
  export declare function issueOf(column: string, error: Extract<FieldParse<unknown>, {
71
78
  success: false;
@@ -95,6 +102,14 @@ export interface RowDecoder {
95
102
  finish<R extends object>(decoded: R): R & {
96
103
  decodeError?: string;
97
104
  };
105
+ /**
106
+ * `finish`, for a read that has a variant to return instead of throwing (#1637): when a
107
+ * required scalar broke, `unreadable` is handed the same message `finish` would throw — every
108
+ * column named — and its result is returned in place of the row.
109
+ */
110
+ finishOr<R extends object, V>(decoded: R, unreadable: (decodeError: string) => V): (R & {
111
+ decodeError?: string;
112
+ }) | V;
98
113
  }
99
114
  /**
100
115
  * One row's decoder. `subject` names the row in a throw (`platform request row "01J…"`),
@@ -1 +1 @@
1
- {"version":3,"file":"row-decode.d.ts","sourceRoot":"","sources":["../src/row-decode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,KAAK,EAAE,KAAK,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE/F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,KAAK,UAAU,CAAC,CAAC,IACb;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,GAC1B;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE;QAAE,MAAM,EAAE,aAAa,CAAC;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,aAAa,CAAC,WAAW,CAAC,CAAA;SAAE,CAAC,CAAA;KAAE,CAAA;CAAE,CAAC;AAEhH,oFAAoF;AACpF,MAAM,WAAW,KAAK,CAAC,CAAC;IACtB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;CAC1C;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,KAA8C,CAAC;AAE7E;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,EAAE,aAA6D,CAAC;AAKjG,sEAAsE;AACtE,wBAAgB,OAAO,CACrB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC,OAAO,CAAC,GAC/D,MAAM,CAIR;AAED,8FAA8F;AAC9F,eAAO,MAAM,QAAQ,mBAAmB,CAAC;AAEzC,MAAM,WAAW,UAAU;IACzB,mGAAmG;IACnG,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,GAAG,CAAC,CAAC;IACjE,oFAAoF;IACpF,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC;IAC/E;;;;;OAKG;IACH,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;IAC1E,mGAAmG;IACnG,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC;IAC7E,8FAA8F;IAC9F,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACrC;;;OAGG;IACH,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,GAAG;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACpE;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,CAwDxE"}
1
+ {"version":3,"file":"row-decode.d.ts","sourceRoot":"","sources":["../src/row-decode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,KAAK,EAAE,KAAK,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE/F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,KAAK,UAAU,CAAC,CAAC,IACb;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,GAC1B;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE;QAAE,MAAM,EAAE,aAAa,CAAC;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,aAAa,CAAC,WAAW,CAAC,CAAA;SAAE,CAAC,CAAA;KAAE,CAAA;CAAE,CAAC;AAEhH,oFAAoF;AACpF,MAAM,WAAW,KAAK,CAAC,CAAC;IACtB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;CAC1C;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,KAA8C,CAAC;AAE7E;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,EAAE,aAA6D,CAAC;AAKjG;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED,sEAAsE;AACtE,wBAAgB,OAAO,CACrB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC,OAAO,CAAC,GAC/D,MAAM,CAIR;AAED,8FAA8F;AAC9F,eAAO,MAAM,QAAQ,mBAAmB,CAAC;AAEzC,MAAM,WAAW,UAAU;IACzB,mGAAmG;IACnG,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,GAAG,CAAC,CAAC;IACjE,oFAAoF;IACpF,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC;IAC/E;;;;;OAKG;IACH,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;IAC1E,mGAAmG;IACnG,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC;IAC7E,8FAA8F;IAC9F,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACrC;;;OAGG;IACH,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,GAAG;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnE;;;;OAIG;IACH,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,CAAC,CAAC;CACvH;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,CA0DxE"}
@@ -18,6 +18,14 @@ export const UNDECODED_ACTOR = actor.parse({ system: 'undecodable' });
18
18
  export const UNDECODED_PERMISSION = permissionKey.parse('undecodable:permission');
19
19
  /** How much of a stored scalar a `marked` field quotes back — a key, not a payload. */
20
20
  const QUOTED_MAX = 200;
21
+ /**
22
+ * Stored text cut to {@link QUOTED_MAX}, with `…` where it was cut — for any decoder that hands a
23
+ * stored value back verbatim (#1637), so an oversized one cannot ride into a report, a log line
24
+ * that repeats every tick, or a screen.
25
+ */
26
+ export function capped(text) {
27
+ return text.length > QUOTED_MAX ? `${text.slice(0, QUOTED_MAX)}…` : text;
28
+ }
21
29
  /** `column: message`, for the first issue a field's schema raised. */
22
30
  export function issueOf(column, error) {
23
31
  const issue = error.issues[0];
@@ -36,6 +44,11 @@ export function rowDecoder(subject, contract) {
36
44
  const undecoded = [];
37
45
  const unreadable = [];
38
46
  const failed = new Set();
47
+ const finishOr = (decoded, onUnreadable) => {
48
+ if (unreadable.length)
49
+ return onUnreadable([...unreadable, ...undecoded].join('; '));
50
+ return undecoded.length ? { ...decoded, decodeError: undecoded.join('; ') } : decoded;
51
+ };
39
52
  return {
40
53
  failed,
41
54
  required(column, field, stored) {
@@ -58,8 +71,7 @@ export function rowDecoder(subject, contract) {
58
71
  const r = field.safeParse(stored);
59
72
  if (r.success)
60
73
  return r.data;
61
- const quoted = JSON.stringify(stored) ?? String(stored);
62
- undecoded.push(`${issueOf(column, r.error)} (stored ${quoted.length > QUOTED_MAX ? `${quoted.slice(0, QUOTED_MAX)}…` : quoted})`);
74
+ undecoded.push(`${issueOf(column, r.error)} (stored ${capped(JSON.stringify(stored) ?? String(stored))})`);
63
75
  failed.add(column);
64
76
  return marker;
65
77
  },
@@ -83,11 +95,11 @@ export function rowDecoder(subject, contract) {
83
95
  return empty;
84
96
  },
85
97
  finish(decoded) {
86
- if (unreadable.length) {
87
- throw new Error(`${subject} cannot be read as a ${contract} — ${[...unreadable, ...undecoded].join('; ')}`);
88
- }
89
- return undecoded.length ? { ...decoded, decodeError: undecoded.join('; ') } : decoded;
98
+ return finishOr(decoded, (why) => {
99
+ throw new Error(`${subject} cannot be read as a ${contract} — ${why}`);
100
+ });
90
101
  },
102
+ finishOr,
91
103
  };
92
104
  }
93
105
  //# sourceMappingURL=row-decode.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"row-decode.js","sourceRoot":"","sources":["../src/row-decode.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"row-decode.js","sourceRoot":"","sources":["../src/row-decode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,aAAa,EAAkC,MAAM,yBAAyB,CAAC;AA+C/F;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAU,KAAK,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;AAE7E;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAkB,aAAa,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;AAEjG,uFAAuF;AACvF,MAAM,UAAU,GAAG,GAAG,CAAC;AAEvB;;;;GAIG;AACH,MAAM,UAAU,MAAM,CAAC,IAAY;IACjC,OAAO,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3E,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,OAAO,CACrB,MAAc,EACd,KAAgE;IAEhE,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC9B,MAAM,EAAE,GAAG,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACpF,OAAO,GAAG,MAAM,GAAG,EAAE,KAAK,KAAK,EAAE,OAAO,IAAI,6BAA6B,EAAE,CAAC;AAC9E,CAAC;AAED,8FAA8F;AAC9F,MAAM,CAAC,MAAM,QAAQ,GAAG,gBAAgB,CAAC;AA+BzC;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,OAAe,EAAE,QAAgB;IAC1D,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;IACjC,MAAM,QAAQ,GAAG,CACf,OAAU,EACV,YAAwC,EACJ,EAAE;QACtC,IAAI,UAAU,CAAC,MAAM;YAAE,OAAO,YAAY,CAAC,CAAC,GAAG,UAAU,EAAE,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACrF,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,WAAW,EAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;IACxF,CAAC,CAAC;IACF,OAAO;QACL,MAAM;QACN,QAAQ,CAAI,MAAc,EAAE,KAAe,EAAE,MAAe;YAC1D,MAAM,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAClC,IAAI,CAAC,CAAC,OAAO;gBAAE,OAAO,CAAC,CAAC,IAAI,CAAC;YAC7B,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;YAC1C,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACnB,OAAO,SAAkB,CAAC;QAC5B,CAAC;QACD,QAAQ,CAAI,MAAc,EAAE,KAAsB,EAAE,MAAe;YACjE,MAAM,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAClC,IAAI,CAAC,CAAC,OAAO;gBAAE,OAAO,CAAC,CAAC,IAAI,CAAC;YAC7B,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;YACzC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACnB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,CAAI,MAAc,EAAE,KAAe,EAAE,MAAe,EAAE,MAAS;YACnE,MAAM,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAClC,IAAI,CAAC,CAAC,OAAO;gBAAE,OAAO,CAAC,CAAC,IAAI,CAAC;YAC7B,SAAS,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,YAAY,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC;YAC3G,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACnB,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,IAAI,CAAI,MAAc,EAAE,KAAe,EAAE,MAAqB,EAAE,KAAQ;YACtE,IAAI,KAAK,GAAY,IAAI,CAAC;YAC1B,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBACpB,IAAI,CAAC;oBACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBAC7B,CAAC;gBAAC,MAAM,CAAC;oBACP,SAAS,CAAC,IAAI,CAAC,GAAG,MAAM,KAAK,QAAQ,EAAE,CAAC,CAAC;oBACzC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;oBACnB,OAAO,KAAK,CAAC;gBACf,CAAC;YACH,CAAC;YACD,MAAM,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YACjC,IAAI,CAAC,CAAC,OAAO;gBAAE,OAAO,CAAC,CAAC,IAAI,CAAC;YAC7B,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;YACzC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACnB,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,CAAmB,OAAU;YACjC,OAAO,QAAQ,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBAC/B,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO,wBAAwB,QAAQ,MAAM,GAAG,EAAE,CAAC,CAAC;YACzE,CAAC,CAAC,CAAC;QACL,CAAC;QACD,QAAQ;KACT,CAAC;AACJ,CAAC"}
@@ -34,6 +34,55 @@ export declare const copyMoveConfirmParams: (confirm: ScopeCopyMoveConfirmation,
34
34
  export declare const COPY_EXPIRED_SQL = "\n SELECT tenant_id, scope_id, script_ref, move_id FROM scope_script_copies\n WHERE state = 'pending' AND (lease_until IS NULL OR lease_until <= ?)\n ORDER BY lease_until, tenant_id, scope_id, script_ref, move_id LIMIT ?";
35
35
  /** Claim one expired entry, re-checked in the write. Params: owner, leaseUntil, the key, now. */
36
36
  export declare const COPY_CLAIM_SQL = "\n UPDATE scope_script_copies SET lease_owner = ?, lease_until = ?\n WHERE tenant_id = ? AND scope_id = ? AND script_ref = ? AND move_id = ?\n AND state = 'pending' AND (lease_until IS NULL OR lease_until <= ?)";
37
+ /** The move id every backfilled entry carries (#1722), which names it as one in a listing. */
38
+ export declare const BACKFILL_MOVE_ID = "backfill:1722";
39
+ /**
40
+ * Record a copy made before the ledger existed, as `retained` (#1722). Never pending, so no move's
41
+ * confirmation and no lease sweep ever acts on it; never `eligible`, because a historic copy has
42
+ * no recorded load stamp for a fenced wipe to compare. Refused under a reap claim, like any new
43
+ * entry, and skipped when the ledger already names the script for this scope in any state: from
44
+ * that entry on the ledger tracks that store, historic data in it included.
45
+ * Params: `copyBackfillParams`.
46
+ */
47
+ export declare const COPY_BACKFILL_SQL = "\n INSERT INTO scope_script_copies (tenant_id, scope_id, script_ref, move_id, state, last_attempt_at)\n SELECT tenant_id, scope_id, ?, ?, 'retained', strftime('%Y-%m-%dT%H:%M:%fZ','now') FROM scopes\n WHERE tenant_id = ? AND scope_id = ? AND reap_claimed_at IS NULL\n AND NOT EXISTS (SELECT 1 FROM scope_script_copies AS copy\n WHERE copy.tenant_id = scopes.tenant_id AND copy.scope_id = scopes.scope_id AND copy.script_ref = ?)";
48
+ export declare const copyBackfillParams: (tenantId: string, scopeId: string, scriptRef: string) => string[];
49
+ /** What a backfill insert did: wrote the entry, found the script already ledgered, or was refused. */
50
+ export type ScopeCopyBackfillResult = 'recorded' | 'ledgered' | 'reaping' | 'missing';
51
+ /**
52
+ * Settle the scope's backfilled entries a tracked entry has taken over (#1722, review r1). The
53
+ * backfill records a script only while no move names it; once a move's own entry for the same
54
+ * script is `done`, that store was wiped under the move's fence or is the scope's route, so the
55
+ * historic data the backfilled entry stood for is gone or reached. Leaving the entry `retained`
56
+ * would send every later reap and erasure to a store that refuses writes behind its tombstone.
57
+ * Run in the same transaction as every write that settles an entry `done`: a settle and a
58
+ * confirming bind, on both adapters. Params: tenantId, scopeId.
59
+ */
60
+ export declare const COPY_BACKFILL_SUPERSEDE_SQL = "\n UPDATE scope_script_copies SET state = 'done', last_attempt_at = strftime('%Y-%m-%dT%H:%M:%fZ','now')\n WHERE tenant_id = ? AND scope_id = ? AND move_id = 'backfill:1722' AND state <> 'done'\n AND EXISTS (SELECT 1 FROM scope_script_copies AS tracked\n WHERE tracked.tenant_id = scope_script_copies.tenant_id AND tracked.scope_id = scope_script_copies.scope_id\n AND tracked.script_ref = scope_script_copies.script_ref AND tracked.move_id <> 'backfill:1722'\n AND tracked.state = 'done')";
61
+ /**
62
+ * The scope row read in the backfill insert's own transaction: what explains an insert that wrote
63
+ * nothing, and the erasure epoch a recorded entry was written under. An erasure claimed before the
64
+ * insert moved the epoch past what it compared (its `shredSubject` row's `before`), so a subject
65
+ * whose erasure's epoch is below this one never reached the recorded copy, whatever order their
66
+ * audit rows landed in. Params: tenantId, scopeId.
67
+ */
68
+ export declare const COPY_BACKFILL_SCOPE_SQL = "SELECT reap_claimed_at, COALESCE(erasure_epoch, 0) AS erasure_epoch FROM scopes WHERE tenant_id = ? AND scope_id = ?";
69
+ /**
70
+ * What an erasure's `shredSubject` row records in `before` (#1722): the erasure epoch it ran under
71
+ * and how it ran. `orchestrated` claimed the scope's copy inventory at that epoch and redacted every
72
+ * copy in it; `direct` took no claim and redacted only the scope's own store, so it never reaches a
73
+ * script copy whatever its epoch. The backfill orders erasures against the copies it records by it.
74
+ */
75
+ export interface ErasureEpochStamp {
76
+ erasureEpoch: number;
77
+ path: 'orchestrated' | 'direct';
78
+ }
79
+ /** `COPY_BACKFILL_SCOPE_SQL`'s row. */
80
+ export interface CopyBackfillScopeRow {
81
+ reap_claimed_at: string | null;
82
+ erasure_epoch: number;
83
+ }
84
+ /** Read the outcome of a backfill insert that wrote nothing, from `COPY_BACKFILL_SCOPE_SQL`'s row. */
85
+ export declare const copyBackfillRefusal: (scope: CopyBackfillScopeRow | undefined) => ScopeCopyBackfillResult;
37
86
  /**
38
87
  * The fence a copy move's restore carries into the destination's own store (#1722). The vertical
39
88
  * that holds the destination has no reach to the directory, so the move's lease travels with
@@ -53,8 +102,6 @@ export interface CopyRestoreFence {
53
102
  notAfter: string;
54
103
  erasureEpoch: number;
55
104
  }
56
- /** How far inside the lease a restore must commit: five minutes, or a quarter of a short lease. */
57
- export declare const copyRestoreFenceMarginMs: (leaseMs: number) => number;
58
105
  /** The fence for a move whose entries were recorded no earlier than `recordedAt` (epoch ms). */
59
106
  export declare const copyRestoreFence: (moveId: string, recordedAt: number, leaseMs: number, erasureEpoch: number) => CopyRestoreFence;
60
107
  /** Whether a restore carrying `fence` may no longer land at `now` (epoch ms). */
@@ -1 +1 @@
1
- {"version":3,"file":"scope-copy-ledger.d.ts","sourceRoot":"","sources":["../src/scope-copy-ledger.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElF;;;;;;;;;;;;;;;;;GAiBG;AAEH,8FAA8F;AAC9F,eAAO,MAAM,wBAAwB,4cAM0B,CAAC;AAEhE,eAAO,MAAM,kBAAkB,YAAa,yBAAyB,OAAO,MAAM,KAAG,MAAM,EACpD,CAAC;AAExC;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,kWAM2C,CAAC;AAE9E,eAAO,MAAM,qBAAqB,YACvB,yBAAyB,YAAY,MAAM,WAAW,MAAM,OAAO,MAAM,KACjF,CAAC,MAAM,GAAG,IAAI,CAAC,EAGjB,CAAC;AAEF,uGAAuG;AACvG,eAAO,MAAM,gBAAgB,oOAG4C,CAAC;AAE1E,iGAAiG;AACjG,eAAO,MAAM,cAAc,4NAG6C,CAAC;AAEzE;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,mGAAmG;AACnG,eAAO,MAAM,wBAAwB,YAAa,MAAM,KAAG,MAAuD,CAAC;AAEnH,gGAAgG;AAChG,eAAO,MAAM,gBAAgB,WACnB,MAAM,cAAc,MAAM,WAAW,MAAM,gBAAgB,MAAM,KACxE,gBAID,CAAC;AAEH,iFAAiF;AACjF,eAAO,MAAM,sBAAsB,UAAW,gBAAgB,OAAO,MAAM,KAAG,OAA2C,CAAC;AAE1H,6EAA6E;AAC7E,eAAO,MAAM,yBAAyB,iFAAiF,CAAC;AAExH,6CAA6C;AAC7C,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,wFAAwF;AACxF,eAAO,MAAM,yBAAyB,6FACsD,CAAC;AAE7F,eAAO,MAAM,iBAAiB,MAAO,kBAAkB,KAAG,eAUxD,CAAC"}
1
+ {"version":3,"file":"scope-copy-ledger.d.ts","sourceRoot":"","sources":["../src/scope-copy-ledger.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElF;;;;;;;;;;;;;;;;;GAiBG;AAEH,8FAA8F;AAC9F,eAAO,MAAM,wBAAwB,4cAM0B,CAAC;AAEhE,eAAO,MAAM,kBAAkB,YAAa,yBAAyB,OAAO,MAAM,KAAG,MAAM,EACpD,CAAC;AAExC;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,kWAM2C,CAAC;AAE9E,eAAO,MAAM,qBAAqB,YACvB,yBAAyB,YAAY,MAAM,WAAW,MAAM,OAAO,MAAM,KACjF,CAAC,MAAM,GAAG,IAAI,CAAC,EAGjB,CAAC;AAEF,uGAAuG;AACvG,eAAO,MAAM,gBAAgB,oOAG4C,CAAC;AAE1E,iGAAiG;AACjG,eAAO,MAAM,cAAc,4NAG6C,CAAC;AAEzE,8FAA8F;AAC9F,eAAO,MAAM,gBAAgB,kBAAkB,CAAC;AAEhD;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,4bAK6E,CAAC;AAE5G,eAAO,MAAM,kBAAkB,aAAc,MAAM,WAAW,MAAM,aAAa,MAAM,KAAG,MAAM,EACnC,CAAC;AAE9D,sGAAsG;AACtG,MAAM,MAAM,uBAAuB,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;AAEtF;;;;;;;;GAQG;AACH,eAAO,MAAM,2BAA2B,sgBAMJ,CAAC;AAErC;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,yHACoF,CAAC;AAEzH;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAAG,YAAY,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,cAAc,GAAG,QAAQ,CAAA;CAAE;AAE5F,uCAAuC;AACvC,MAAM,WAAW,oBAAoB;IAAG,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE;AAE/F,sGAAsG;AACtG,eAAO,MAAM,mBAAmB,UAAW,oBAAoB,GAAG,SAAS,KAAG,uBACA,CAAC;AAE/E;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAKD,gGAAgG;AAChG,eAAO,MAAM,gBAAgB,WACnB,MAAM,cAAc,MAAM,WAAW,MAAM,gBAAgB,MAAM,KACxE,gBAID,CAAC;AAEH,iFAAiF;AACjF,eAAO,MAAM,sBAAsB,UAAW,gBAAgB,OAAO,MAAM,KAAG,OAA2C,CAAC;AAE1H,6EAA6E;AAC7E,eAAO,MAAM,yBAAyB,iFAAiF,CAAC;AAExH,6CAA6C;AAC7C,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,wFAAwF;AACxF,eAAO,MAAM,yBAAyB,6FACsD,CAAC;AAE7F,eAAO,MAAM,iBAAiB,MAAO,kBAAkB,KAAG,eAUxD,CAAC"}
@@ -54,8 +54,51 @@ export const COPY_CLAIM_SQL = `
54
54
  UPDATE scope_script_copies SET lease_owner = ?, lease_until = ?
55
55
  WHERE tenant_id = ? AND scope_id = ? AND script_ref = ? AND move_id = ?
56
56
  AND state = 'pending' AND (lease_until IS NULL OR lease_until <= ?)`;
57
+ /** The move id every backfilled entry carries (#1722), which names it as one in a listing. */
58
+ export const BACKFILL_MOVE_ID = 'backfill:1722';
59
+ /**
60
+ * Record a copy made before the ledger existed, as `retained` (#1722). Never pending, so no move's
61
+ * confirmation and no lease sweep ever acts on it; never `eligible`, because a historic copy has
62
+ * no recorded load stamp for a fenced wipe to compare. Refused under a reap claim, like any new
63
+ * entry, and skipped when the ledger already names the script for this scope in any state: from
64
+ * that entry on the ledger tracks that store, historic data in it included.
65
+ * Params: `copyBackfillParams`.
66
+ */
67
+ export const COPY_BACKFILL_SQL = `
68
+ INSERT INTO scope_script_copies (tenant_id, scope_id, script_ref, move_id, state, last_attempt_at)
69
+ SELECT tenant_id, scope_id, ?, ?, 'retained', strftime('%Y-%m-%dT%H:%M:%fZ','now') FROM scopes
70
+ WHERE tenant_id = ? AND scope_id = ? AND reap_claimed_at IS NULL
71
+ AND NOT EXISTS (SELECT 1 FROM scope_script_copies AS copy
72
+ WHERE copy.tenant_id = scopes.tenant_id AND copy.scope_id = scopes.scope_id AND copy.script_ref = ?)`;
73
+ export const copyBackfillParams = (tenantId, scopeId, scriptRef) => [scriptRef, BACKFILL_MOVE_ID, tenantId, scopeId, scriptRef];
74
+ /**
75
+ * Settle the scope's backfilled entries a tracked entry has taken over (#1722, review r1). The
76
+ * backfill records a script only while no move names it; once a move's own entry for the same
77
+ * script is `done`, that store was wiped under the move's fence or is the scope's route, so the
78
+ * historic data the backfilled entry stood for is gone or reached. Leaving the entry `retained`
79
+ * would send every later reap and erasure to a store that refuses writes behind its tombstone.
80
+ * Run in the same transaction as every write that settles an entry `done`: a settle and a
81
+ * confirming bind, on both adapters. Params: tenantId, scopeId.
82
+ */
83
+ export const COPY_BACKFILL_SUPERSEDE_SQL = `
84
+ UPDATE scope_script_copies SET state = 'done', last_attempt_at = strftime('%Y-%m-%dT%H:%M:%fZ','now')
85
+ WHERE tenant_id = ? AND scope_id = ? AND move_id = '${BACKFILL_MOVE_ID}' AND state <> 'done'
86
+ AND EXISTS (SELECT 1 FROM scope_script_copies AS tracked
87
+ WHERE tracked.tenant_id = scope_script_copies.tenant_id AND tracked.scope_id = scope_script_copies.scope_id
88
+ AND tracked.script_ref = scope_script_copies.script_ref AND tracked.move_id <> '${BACKFILL_MOVE_ID}'
89
+ AND tracked.state = 'done')`;
90
+ /**
91
+ * The scope row read in the backfill insert's own transaction: what explains an insert that wrote
92
+ * nothing, and the erasure epoch a recorded entry was written under. An erasure claimed before the
93
+ * insert moved the epoch past what it compared (its `shredSubject` row's `before`), so a subject
94
+ * whose erasure's epoch is below this one never reached the recorded copy, whatever order their
95
+ * audit rows landed in. Params: tenantId, scopeId.
96
+ */
97
+ export const COPY_BACKFILL_SCOPE_SQL = 'SELECT reap_claimed_at, COALESCE(erasure_epoch, 0) AS erasure_epoch FROM scopes WHERE tenant_id = ? AND scope_id = ?';
98
+ /** Read the outcome of a backfill insert that wrote nothing, from `COPY_BACKFILL_SCOPE_SQL`'s row. */
99
+ export const copyBackfillRefusal = (scope) => !scope ? 'missing' : scope.reap_claimed_at !== null ? 'reaping' : 'ledgered';
57
100
  /** How far inside the lease a restore must commit: five minutes, or a quarter of a short lease. */
58
- export const copyRestoreFenceMarginMs = (leaseMs) => Math.min(5 * 60_000, Math.floor(leaseMs / 4));
101
+ const copyRestoreFenceMarginMs = (leaseMs) => Math.min(5 * 60_000, Math.floor(leaseMs / 4));
59
102
  /** The fence for a move whose entries were recorded no earlier than `recordedAt` (epoch ms). */
60
103
  export const copyRestoreFence = (moveId, recordedAt, leaseMs, erasureEpoch) => ({
61
104
  moveId,
@@ -1 +1 @@
1
- {"version":3,"file":"scope-copy-ledger.js","sourceRoot":"","sources":["../src/scope-copy-ledger.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;GAiBG;AAEH,8FAA8F;AAC9F,MAAM,CAAC,MAAM,wBAAwB,GAAG;;;;;;+DAMuB,CAAC;AAEhE,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,OAAkC,EAAE,GAAW,EAAY,EAAE,CAC9F,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAExC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;6EAMwC,CAAC;AAE9E,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,OAAkC,EAAE,QAAgB,EAAE,OAAe,EAAE,GAAW,EAC/D,EAAE,CAAC;IACtB,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,EAAE,SAAS,IAAI,IAAI,EAAE,OAAO,CAAC,YAAY,EAAE,QAAQ,IAAI,IAAI;IAC/F,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM;CACvC,CAAC;AAEF,uGAAuG;AACvG,MAAM,CAAC,MAAM,gBAAgB,GAAG;;;yEAGyC,CAAC;AAE1E,iGAAiG;AACjG,MAAM,CAAC,MAAM,cAAc,GAAG;;;wEAG0C,CAAC;AAsBzE,mGAAmG;AACnG,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,OAAe,EAAU,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;AAEnH,gGAAgG;AAChG,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,MAAc,EAAE,UAAkB,EAAE,OAAe,EAAE,YAAoB,EACvD,EAAE,CAAC,CAAC;IACtB,MAAM;IACN,QAAQ,EAAE,IAAI,IAAI,CAAC,UAAU,GAAG,OAAO,GAAG,wBAAwB,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,EAAE;IAC1F,YAAY;CACb,CAAC,CAAC;AAEH,iFAAiF;AACjF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,KAAuB,EAAE,GAAW,EAAW,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;AAE1H,6EAA6E;AAC7E,MAAM,CAAC,MAAM,yBAAyB,GAAG,8EAA8E,CAAC;AAexH,wFAAwF;AACxF,MAAM,CAAC,MAAM,yBAAyB,GACpC,0FAA0F,CAAC;AAE7F,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAqB,EAAmB,EAAE,CAAC,CAAC;IAC5E,QAAQ,EAAE,CAAC,CAAC,SAAqB;IACjC,OAAO,EAAE,CAAC,CAAC,QAAmB;IAC9B,SAAS,EAAE,CAAC,CAAC,UAAU;IACvB,MAAM,EAAE,CAAC,CAAC,OAAO;IACjB,KAAK,EAAE,CAAC,CAAC,KAAiC;IAC1C,SAAS,EAAE,CAAC,CAAC,UAAU;IACvB,QAAQ,EAAE,CAAC,CAAC,QAAQ;IACpB,IAAI,EAAE,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,KAAK,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;IACrE,UAAU,EAAE,CAAC,CAAC,WAAW;CAC1B,CAAC,CAAC"}
1
+ {"version":3,"file":"scope-copy-ledger.js","sourceRoot":"","sources":["../src/scope-copy-ledger.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,17 @@
1
1
  import type { ModuleLog } from './module-log.js';
2
+ import type { BoundOperations } from './module-operations.js';
2
3
  import type { DeliveryRefusal } from './delivery-refusal.js';
3
4
  import type { ScopeRoleHolder } from './scope-role-admin.js';
5
+ import type { ScopeCopyBackfillResult } from './scope-copy-ledger.js';
4
6
  import type { SubjectRedactionCounts } from './subject-redaction.js';
5
- import type { OnBehalfOf, ExportReadInput, ExportedBatch, ImportBatch, ImportedEvent, ImportResult, ImportState, ImportCursorMove, ImportCursorMoved, AdminAction, BecomeCapabilityInput, CapabilityExchange, CapabilityFilter, CapabilityId, CapabilityPage, MintedCapability, ListPage, ConnectLink, ConnectLinkConsume, ConnectLinkFilter, ConnectLinkKey, ConsumeConnectLinkInput, MintConnectLinkInput, Connection, ConnectionFilter, ConnectionId, ConnectionGrant, ConnectionGrantRecord, ConnectionSecret, CreateConnectionInput, OpenConnection, ProjectedConnectionGrant, ProjectedConnectionKey, AccessLogEntry, DelegatedReadRecord, OwnerTransferAudit, MemberChangeAudit, PeerBindingAudit, CopyMarkAudit, BindHostnameInput, AdminLogEntry, OpsFailureEntry, PlatformRequestDrainTotalsEntry, SweepRunEntry, SweepRunKind, SweepRunOutcome, ModelUsageEntry, ModelUsageSummary, CapabilityGrant, CreateTenantInput, Decision, Instant, DomainEvent, DomainEventInput, PlatformRequestInput, PlatformRequestId, PlatformRequest, PlatformRequestFilter, PlatformRequestStatus, PlatformRequestFailure, PlatformOutcomeEvent, EntitlementGrant, EntitlementGrantInput, EntitlementView, MeterReading, EntityRef, IdentityLink, IdentityPool, Jurisdiction, ModuleId, ModuleManifest, ScheduleSpec, SystemGrant, PeerGrantsStatusEntry, SystemGrantsStatusEntry, SystemSwitchRecord, SystemSwitch, SystemSwitchResult, PeerCoverage, PeerSwitch, PeerSwitchResult, VerticalCaller, VerticalResolution, PeerBinding, PeerInstanceResolution, CreateOrgInput, Node, Org, OrgId, OrgMembership, PermissionKey, PlatformActorId, ChannelName, ExportBreak, ChannelHistoryEntry, DnsRecord, HostnameBinding, HostnameStatus, PromotionAcknowledgement, BindAcknowledgement, PublishVersionInput, RegisterVerticalInput, VerticalServingState, RouteTarget, DirectoryDump, IdentityMembership, PrincipalId, ResolvedIdentity, RoleAssignment, RoleDefinition, QueryScopeInput, ReadScopeTableInput, Scope, ScopeDump, SubjectShredReceipt, ScopeQueryResult, ScopeId, ScopeStatus, ScopeTable, DenialFilter, DenialSummary, RefusalFilter, RefusalRecord, PermissionDenial, Coverage, BeginImpersonationInput, ImpersonationFilter, ImpersonationSession, ImpersonationSessionId, ScopeTablePage, StorageShape, Tenant, TenantId, TenantRole, TenantStoreHandle, AttachmentRecord, BlobStoreHandle, Visibility, Vertical, VerticalChannel, VerticalVersion, TenantStatus, Page, CountedPage, FreshnessSpec, EntityHistoryInput, EventFacetInput, EventCauseInput, EventEffectsInput, EffectsTree, InvocationEventsInput, InvocationEvents, DeadLettersInput, DeadLetter, LifecycleFlowInput, LifecycleFlowResult, OperationSeriesInput, OperationSeriesResult, CauseChain, EventFacetResult, HistoryEntry, ErrorCode, PlatformRequestFailureOrigin, IssueEntry, IssueStatus, IssueStatusInput, FindingEntry, FindingFilter, FindingRuleEntry, FindingRuleInput, FindingStatusInput, DeclaredMigration, CheckSubject, EntityGrantShape } from '@substrat-run/contracts';
7
+ import type { OnBehalfOf, ExportReadInput, ExportedBatch, ImportBatch, ImportedEvent, ImportResult, ImportState, ImportCursorMove, ImportCursorMoved, AdminAction, BecomeCapabilityInput, CapabilityExchange, CapabilityFilter, CapabilityId, CapabilityPage, MintedCapability, ListPage, ConnectLink, ConnectLinkConsume, ConnectLinkFilter, ConnectLinkKey, ConsumeConnectLinkInput, MintConnectLinkInput, Connection, ConnectionFilter, ConnectionId, ConnectionGrant, ConnectionGrantRecord, ConnectionSecret, CreateConnectionInput, OpenConnection, ProjectedConnectionGrant, ProjectedConnectionKey, AccessLogEntry, DelegatedReadRecord, OwnerTransferAudit, MemberChangeAudit, PeerBindingAudit, CopyMarkAudit, BindHostnameInput, AdminLogEntry, OpsFailureEntry, PlatformRequestDrainTotalsEntry, SweepRunEntry, SweepRunKind, SweepRunOutcome, ModelUsageEntry, ModelUsageSummary, CapabilityGrant, CreateTenantInput, Decision, Instant, DomainEvent, DomainEventInput, PlatformRequestInput, PlatformRequestId, PlatformRequestEntry, PlatformRequestFilter, PlatformRequestStatus, PlatformRequestFailure, PlatformOutcomeEvent, EntitlementGrant, EntitlementGrantInput, EntitlementView, MeterReading, ScopeStorageSample, EntityRef, IdentityLink, IdentityPool, Jurisdiction, ModuleId, ModuleManifest, ScheduleSpec, SystemGrant, PeerGrantsStatusEntry, SystemGrantsStatusEntry, SystemSwitchRecord, SystemSwitch, SystemSwitchResult, PeerCoverage, PeerSwitch, PeerSwitchResult, VerticalCaller, VerticalResolution, PeerBinding, PeerInstanceResolution, CreateOrgInput, Node, Org, OrgId, OrgMembership, PermissionKey, PlatformActorId, ChannelName, ExportBreak, ChannelHistoryEntry, DnsRecord, HostnameBinding, HostnameStatus, PromotionAcknowledgement, BindAcknowledgement, PublishVersionInput, RegisterVerticalInput, VerticalServingState, RouteTarget, DirectoryDump, IdentityMembership, PrincipalId, ResolvedIdentity, RoleAssignment, RoleDefinition, QueryScopeInput, ReadScopeTableInput, Scope, ScopeDump, SubjectShredReceipt, ScopeQueryResult, ScopeId, ScopeStatus, ScopeTable, DenialFilter, DenialSummary, RefusalFilter, RefusalRecord, PermissionDenial, Coverage, BeginImpersonationInput, ImpersonationFilter, ImpersonationSession, ImpersonationSessionId, ScopeTablePage, StorageShape, Tenant, TenantId, TenantRole, TenantStoreHandle, AttachmentRecord, BlobStoreHandle, Visibility, Vertical, VerticalChannel, VerticalVersion, TenantStatus, Page, CountedPage, FreshnessSpec, EntityHistoryInput, EventFacetInput, EventCauseInput, EventEffectsInput, EffectsTree, InvocationEventsInput, InvocationEvents, DeadLettersInput, DeadLetter, LifecycleFlowInput, LifecycleFlowResult, OperationSeriesInput, OperationSeriesResult, CauseChain, EventFacetResult, HistoryEntry, ErrorCode, PlatformRequestFailureOrigin, IssueEntry, IssueStatus, IssueStatusInput, FindingEntry, FindingFilter, FindingRuleEntry, FindingRuleInput, FindingStatusInput, DeclaredMigration, CheckSubject, EntityGrantShape } from '@substrat-run/contracts';
6
8
  import type { ConnectionUseOutcome } from './connector-calls.js';
7
9
  import type { CapabilityVerbs } from './capability.js';
8
10
  import type { AuditedOperationRef, AuditedOperationRow } from './audit-outcome.js';
9
11
  import { type EntityStateName } from '@substrat-run/contracts';
10
12
  import type { ModelUsageFilter, ModelUsageInput, ModelUsageWindow } from './model-usage.js';
11
13
  import type { FindingPruneReport } from './findings.js';
14
+ import type { ScopeStorageAttempt, ScopeStorageFilter, ScopeStorageReadingInput } from './storage-gauge.js';
12
15
  import type { SealedSecret } from './secret-box.js';
13
16
  import type { OnSubjectErased } from './module-erasure.js';
14
17
  import type { SystemSwitchReassert, SystemSwitchReassertOptions, SystemSwitchRecordFilter } from './system-switch-record.js';
@@ -184,8 +187,14 @@ export interface OperationContext {
184
187
  *
185
188
  * Read-only by construction: the kernel owns every write to this table (rule 3 forbids module
186
189
  * code writing `_substrat_*`), so an intent's status is only ever the platform's answer.
190
+ *
191
+ * **A row whose identity does not decode comes back as an `UndecodablePlatformRequest`**
192
+ * (#1637) — its id, kind, status, attempts or time as stored, and why — beside every other row,
193
+ * instead of throwing for the whole list. Narrow with `isUndecodablePlatformRequest` before
194
+ * reading anything else. Only a restored dump can hold such a row; a healthy journal never
195
+ * returns one.
187
196
  */
188
- platformRequests(filter?: PlatformRequestFilter): PlatformRequest[];
197
+ platformRequests(filter?: PlatformRequestFilter): PlatformRequestEntry[];
189
198
  /**
190
199
  * This entity's version (#901) — the ULID of the last event about it, or
191
200
  * `null` if nothing has ever been emitted about it.
@@ -665,7 +674,7 @@ export interface InvokeOptions {
665
674
  * call. That is the join a trace view needs and the one nothing could make: the
666
675
  * runtime's own request id is stamped by the log platform at ingestion, so no
667
676
  * vertical code can read it, and a trace does not cross the dispatch hop
668
- * (`invocation-log.ts`, verified in production).
677
+ * (vertical-host's `invocation-log.ts`, verified in production).
669
678
  *
670
679
  * So the platform mints one, puts it in the invocation log line, and carries it
671
680
  * here — where it is stamped onto every event the call emits. That makes an
@@ -1503,86 +1512,28 @@ export declare function consumersFor<const C extends readonly EventContract[]>()
1503
1512
  export interface ModuleRegistration<C extends readonly EventContract[] = []> {
1504
1513
  manifest: ModuleManifest;
1505
1514
  migrations?: SqlMigration[];
1506
- operations?: Record<string, OperationHandler<never, unknown>>;
1507
- /**
1508
- * name → the schema the host parses an invocation's input against, BEFORE the
1509
- * guards and the handler see it (#893).
1510
- *
1511
- * Derived from the declared operation surface — `operationInputsOf(ops)` — and
1512
- * never written a second time. A module that declares its operations gets the
1513
- * parse by handing the same object over:
1514
- *
1515
- * ```ts
1516
- * operations: { 'rally/book': bookOp, … },
1517
- * operationInputs: operationInputsOf(rallyOperations),
1518
- * ```
1519
- *
1520
- * **This is where "parse, don't trust" is kept, rather than in 85 handlers.**
1521
- * `OperationShape.input` calls itself *"the SAME Zod object the handler
1522
- * parses"* and across the fleet it mostly was not — rally declared 32 inputs
1523
- * and parsed 2. One place that cannot be forgotten beats a rule every new
1524
- * operation has to remember, which is the same argument `mountOperations`
1525
- * already makes for the page trio.
1526
- *
1527
- * A name here that no operation binds is an error: it is a schema enforcing
1528
- * nothing, and it reads as coverage. A bound operation with no entry is
1529
- * allowed and means what it always meant — nothing was declared to parse.
1530
- *
1531
- * **It also carries the declared surface (#119).** `operationInputsOf` records, for the frozen
1532
- * map it returns, every declared operation and the entity each addresses by id. The host DERIVES
1533
- * its trash refusal from that — nothing else is handed over — and a module with a trashable
1534
- * entity must pass that map as returned, with every operation it binds declared in it.
1535
- *
1536
- * Typed structurally rather than as `z.ZodType` so the kernel keeps its single
1537
- * dependency and no zod version is pinned by the scope-host contract. The
1538
- * shape is the whole surface the host uses: throw to refuse, return the value
1539
- * to accept.
1540
- */
1541
- operationInputs?: Record<string, {
1542
- parse(value: unknown): unknown;
1543
- }>;
1544
1515
  /**
1545
- * name → the entity whose version this operation's `If-Match` is compared
1546
- * against, and the input field carrying its id (#129).
1547
- *
1548
- * Derived from the declared operation surface — `operationConcurrencyOf(ops)` —
1549
- * and never written a second time, exactly as `operationInputs` is:
1516
+ * The module's operations: its handlers and, derived from their declaration, the input schemas
1517
+ * the host parses with, the `If-Match` concurrency map and the idempotency opt-outs (#1835).
1518
+ * From `operationsFor(declaration)(handlers)` or, for a module with no declared surface,
1519
+ * `undeclaredOperations(reason, handlers)` — never an object literal:
1550
1520
  *
1551
1521
  * ```ts
1552
- * operations: { 'callout/update-customer': updateCustomerOp, … },
1553
- * operationInputs: operationInputsOf(calloutOperations),
1554
- * operationConcurrency: operationConcurrencyOf(calloutOperations),
1522
+ * ...operationsFor(rallyOperations)({ 'rally/book': bookOp, … }),
1555
1523
  * ```
1556
1524
  *
1557
- * **The host compares, not the handler.** A precondition a handler evaluates is
1558
- * a precondition a handler can forget, and the one that is forgotten is
1559
- * indistinguishable from one that passed. Here the comparison happens between
1560
- * `BEGIN` and the guards for every caller and every transport, or the operation
1561
- * does not claim to have it.
1525
+ * **This is where "parse, don't trust" is kept, rather than in 85 handlers** (#893).
1526
+ * `OperationShape.input` calls itself *"the SAME Zod object the handler parses"* and across
1527
+ * the fleet it mostly was not — rally declared 32 inputs and parsed 2. The schemas, the
1528
+ * concurrency the host compares between `BEGIN` and the guards (#129) and the opt-outs (#116)
1529
+ * used to be three more optional fields beside the handlers, so a module could hand over the
1530
+ * handlers and forget the rest, or pair them with another declaration's. One value closes both.
1562
1531
  *
1563
- * A name here that no operation binds is an error, for the same reason it is on
1564
- * `operationInputs`: it reads as coverage while enforcing nothing.
1532
+ * A schema or a concurrency entry naming no bound operation is an error: it enforces nothing
1533
+ * and reads as coverage. The inputs also carry the declared surface (#119) the host derives
1534
+ * its trash refusal from, so a module with a trashable entity must bind through `operationsFor`.
1565
1535
  */
1566
- operationConcurrency?: Record<string, {
1567
- entity: string;
1568
- idFrom: string;
1569
- }>;
1570
- /**
1571
- * The operations that declared `idempotency: false` (#116) — the ones whose
1572
- * response must not be recorded, and which therefore refuse an
1573
- * `Idempotency-Key` instead of honouring it.
1574
- *
1575
- * Derived like the two above, and never written a second time:
1576
- *
1577
- * ```ts
1578
- * operationIdempotencyOptOuts: operationIdempotencyOptOutsOf(calloutOperations),
1579
- * ```
1580
- *
1581
- * A list of refusals rather than a list of participants, because that is what
1582
- * the declaration is. Absent means every operation honours a key, which is the
1583
- * default and the reason there is nothing to remember.
1584
- */
1585
- operationIdempotencyOptOuts?: readonly string[];
1536
+ operations?: BoundOperations;
1586
1537
  /**
1587
1538
  * eventType → handler; the types must appear in manifest.events.consumes.
1588
1539
  *
@@ -1719,11 +1670,20 @@ export interface HostAdmin {
1719
1670
  * something was fully shared with as a holder.
1720
1671
  *
1721
1672
  * Bounded: `batch` rows of work (default 500, an integer from 1 to 5000, or `validation_failed`)
1722
- * per scope transaction, backfill included, repeated until a pass finishes — so it is safe
1723
- * on a large scope, and finishes on a re-run if interrupted. Each (person, entity) topped up is
1673
+ * per scope transaction, backfill included, and at most ten markers read per row of work, read
1674
+ * on their own index (#2083). Each pass resumes where the last one stopped, until one finds
1675
+ * nothing left, so it is safe on a large scope whether or not anything changed, and finishes on
1676
+ * a re-run if interrupted. A holder an older deployment grants the shape to while it runs, behind
1677
+ * the point it has reached: if they lack a key the shape gained, the next reconcile tops them up.
1678
+ * If they hold a key the shape retired, a confirming walk from the first marker, which every
1679
+ * retirement runs before it records itself finished, takes it back. Only a grant landing behind
1680
+ * that confirming walk keeps the key, as one landing after the retirement finished does. Each (person, entity) topped up is
1724
1681
  * an `entity.grants-topped-up` event on the entity, and each one retired keys were taken from an
1725
1682
  * `entity.grants-retired` event. Audited as `reconcileEntityGrantShapes` when it changed
1726
- * anything. Returns how many (person, entity) it topped up, and how many it retired keys from.
1683
+ * anything. Returns how many (person, entity) it topped up, and how many it retired keys from;
1684
+ * plus, only when nonzero, `retirementsLeftOpen`: shapes whose retirement kept meeting new
1685
+ * grants of a retired key (`SHAPE_RETIRE_CONFIRMS_MAX` confirming walks that took keys) and was
1686
+ * left for the next reconcile to run again, unrecorded.
1727
1687
  */
1728
1688
  reconcileEntityGrantShapes(actor: PlatformActorId, node: {
1729
1689
  tenantId: TenantId;
@@ -1733,6 +1693,7 @@ export interface HostAdmin {
1733
1693
  }): Promise<{
1734
1694
  toppedUp: number;
1735
1695
  retired: number;
1696
+ retirementsLeftOpen?: number;
1736
1697
  }>;
1737
1698
  /** Grant to an organization (portal customers); members reach it via membership tuples. */
1738
1699
  /**
@@ -1952,14 +1913,13 @@ export interface HostAdmin {
1952
1913
  }): Promise<PeerGrantsStatusEntry[]>;
1953
1914
  /**
1954
1915
  * Mint a `become` capability on a scope (#1672): whoever exchanges its secret yields
1955
- * `input.principal` rather than a session — the shape an owner claim link and a member
1956
- * invite are, so both can move onto this primitive later. The secret is returned once;
1957
- * the scope keeps its hash. Expiry and a use limit are required.
1916
+ * `input.principal` rather than a session — the shape an owner claim link is. The secret is
1917
+ * returned once; the scope keeps its hash. Expiry and a use limit are required.
1958
1918
  *
1959
- * Platform-only in this first cut, deliberately: `become` is impersonation by another
1960
- * name, and the bound on who may mint one from module code is designed with the claim
1961
- * and invite migrations. Audited in the admin log (never the secret, never its hash).
1962
- * Refuses an unknown or inactive scope, as `getScope` does.
1919
+ * `become` is impersonation by another name, so module code never mints one. This is the
1920
+ * platform's mint; a principal mints one only through an adapter's bounded host verb (a
1921
+ * member invite, `becomeMintCheck`, #1686). Audited in the admin log (never the secret, never
1922
+ * its hash). Refuses an unknown or inactive scope, as `getScope` does.
1963
1923
  */
1964
1924
  mintCapability(actor: PlatformActorId, tenantId: TenantId, scopeId: ScopeId, input: BecomeCapabilityInput): Promise<MintedCapability>;
1965
1925
  /**
@@ -2338,6 +2298,19 @@ export interface HostAdmin {
2338
2298
  opts?: {
2339
2299
  claimedBy?: string;
2340
2300
  }): Promise<boolean>;
2301
+ /**
2302
+ * Record a copy made before this ledger existed (#1722's backfill) as `retained`: reached by reap
2303
+ * and erasure, never wiped by the sweep. One entry per (scope, script), under `BACKFILL_MOVE_ID`.
2304
+ * Answers `ledgered`, writing nothing, when the ledger already names the script for the scope in
2305
+ * any state; `reaping` under a reap claim; `missing` for an unknown scope. Never throws for those,
2306
+ * so a backfill page reports each one instead of stopping. A recorded entry is audited as
2307
+ * `backfillScopeCopy`.
2308
+ */
2309
+ backfillScopeScriptCopy(actor: PlatformActorId, tenantId: TenantId, scopeId: ScopeId, scriptRef: string,
2310
+ /** The admin-log row the script was read from, named in the `backfillScopeCopy` row a recorded entry writes. */
2311
+ opts?: {
2312
+ fromLogId?: string;
2313
+ }): Promise<ScopeCopyBackfillResult>;
2341
2314
  /** Move a failed retry to the back of the due queue without changing its state. */
2342
2315
  touchScopeScriptCopy(actor: PlatformActorId, tenantId: TenantId, scopeId: ScopeId, scriptRef: string, moveId: string): Promise<void>;
2343
2316
  listScopeScriptCopies(actor: PlatformActorId, filter: {
@@ -2890,7 +2863,12 @@ export interface HostAdmin {
2890
2863
  suspendScope(actor: PlatformActorId, tenantId: TenantId, scopeId: ScopeId): Promise<void>;
2891
2864
  /** suspended → active. */
2892
2865
  unsuspendScope(actor: PlatformActorId, tenantId: TenantId, scopeId: ScopeId): Promise<void>;
2893
- /** active|suspended → archived. Stops the active-scope meter (§9). */
2866
+ /**
2867
+ * provisioning|active|suspended → archived. Stops the active-scope meter (§9). A status
2868
+ * change only: the storage stays until `reapScope`. Records the status it left as
2869
+ * `archivedFromStatus` (#1524), so a scope abandoned while still provisioning, which never
2870
+ * held data, is not metered for storage.
2871
+ */
2894
2872
  archiveScope(actor: PlatformActorId, tenantId: TenantId, scopeId: ScopeId): Promise<void>;
2895
2873
  /**
2896
2874
  * archived → active. A RESTORE, never a flag flip (control-plane.md §4.2):
@@ -3367,6 +3345,33 @@ export interface HostAdmin {
3367
3345
  * to `null`.
3368
3346
  */
3369
3347
  pruneTelemetry?(actor: PlatformActorId, limit: number): Promise<TelemetryPruneReport>;
3348
+ /**
3349
+ * The stored storage gauge (#1524): record the scheduled pass's attempts to read scope
3350
+ * database sizes. Each attempt replaces the scope's attempt row (what the pass picks due
3351
+ * scopes by); a successful one also writes the day's sample, one row per (scope, UTC day),
3352
+ * a later same-day reading replacing an earlier one. A failed one leaves the last sample
3353
+ * standing. Rows are written only for a stored (not provisioning, not reaped) scope the directory holds under the named
3354
+ * tenant. Returns how many SAMPLE rows were written. Not audited, like `recordSweepRun`:
3355
+ * retention-bounded telemetry, not evidence.
3356
+ *
3357
+ * The gauge methods are optional, and the sweep's storage phase is skipped on a host that
3358
+ * lacks them, so an adapter built before #1524 still satisfies `HostAdmin`.
3359
+ */
3360
+ recordScopeStorage?(actor: PlatformActorId, readings: readonly ScopeStorageReadingInput[]): Promise<{
3361
+ recorded: number;
3362
+ }>;
3363
+ /**
3364
+ * Stored storage samples (#1524) — the latest per scope, or a bounded history. See
3365
+ * `ScopeStorageFilter`. A directory read that wakes no scope. Access-logged (K-24).
3366
+ */
3367
+ listScopeStorage?(actor: PlatformActorId, filter?: ScopeStorageFilter): Promise<ScopeStorageSample[]>;
3368
+ /** Every stored scope's latest storage-read attempt (#1524): the storage phase's due list. Access-logged. */
3369
+ listScopeStorageAttempts?(actor: PlatformActorId): Promise<ScopeStorageAttempt[]>;
3370
+ /**
3371
+ * Delete storage samples past `STORAGE_GAUGE_RETENTION_MONTHS`, oldest first and at most
3372
+ * `limit` per call, so a backlog drains over passes. Returns how many went. Not audited.
3373
+ */
3374
+ pruneScopeStorage?(actor: PlatformActorId, limit: number): Promise<number>;
3370
3375
  /**
3371
3376
  * A staff verdict on one issue (#1233): resolve, ignore, or reopen. `regressed`
3372
3377
  * is ingest's word and not accepted here. Returns the updated row, or undefined
@@ -4875,8 +4880,11 @@ export interface ScopeHost {
4875
4880
  * `ctx.requestPlatform` awaiting the platform's drain. Fleet maintenance, no actor (the same
4876
4881
  * class as `drainDue`). The platform reads these, executes each with `HostAdmin` authority, and
4877
4882
  * journals the outcome via `settlePlatformRequest` — the read-here/effect-there executor shape.
4883
+ *
4884
+ * A row whose identity does not decode is returned as an `UndecodablePlatformRequest` (#1637),
4885
+ * never thrown for the queue; the drain runs no handler on one.
4878
4886
  */
4879
- listPlatformRequests(tenantId: TenantId, scopeId: ScopeId): Promise<PlatformRequest[]>;
4887
+ listPlatformRequests(tenantId: TenantId, scopeId: ScopeId): Promise<PlatformRequestEntry[]>;
4880
4888
  /**
4881
4889
  * The scope's intent JOURNAL — every intent in whatever state it settled, newest first (#618).
4882
4890
  *
@@ -4887,9 +4895,11 @@ export interface ScopeHost {
4887
4895
  * SQL. This is the read that surfaces it: `kind` narrows to one intent family
4888
4896
  * (`connector:scrive`), `status` to one outcome, `limit` to a recency window.
4889
4897
  *
4890
- * Fleet maintenance, no actor — same class as the pending read it complements.
4898
+ * Fleet maintenance, no actor — same class as the pending read it complements. Returns an
4899
+ * `UndecodablePlatformRequest` for a row whose identity does not decode (#1637), as the
4900
+ * pending read does.
4891
4901
  */
4892
- listPlatformRequestHistory(tenantId: TenantId, scopeId: ScopeId, filter?: PlatformRequestFilter): Promise<PlatformRequest[]>;
4902
+ listPlatformRequestHistory(tenantId: TenantId, scopeId: ScopeId, filter?: PlatformRequestFilter): Promise<PlatformRequestEntry[]>;
4893
4903
  /**
4894
4904
  * Journal a platform-request outcome after the coordinator ran it: `done`, `failed` (terminal),
4895
4905
  * or `pending` (transient — retried on a later drain). `result` persists across retries (a
@@ -5043,26 +5053,6 @@ export interface LiveReadSurface<Req extends LiveUpgradeRequest = LiveUpgradeReq
5043
5053
  expiresAt?: string;
5044
5054
  }): Promise<Res>;
5045
5055
  }
5046
- /**
5047
- * The close codes a live socket ends with, so a client can tell "try again" from "poll".
5048
- *
5049
- * - `1008` (policy): the subscriber may no longer watch what it subscribed to — a
5050
- * `checkedWithin` gate refused, or the session that opened it ended. A reconnect meets
5051
- * the handshake's own refusal.
5052
- * - `4429`: this principal already holds `LIVE_SOCKETS_PER_PRINCIPAL` sockets on the scope.
5053
- * Not a reason to retry: the client should poll, which it does anyway, and stop asking.
5054
- */
5055
- export declare const LIVE_CLOSE: {
5056
- readonly revoked: 1008;
5057
- readonly tooMany: 4429;
5058
- };
5059
- /**
5060
- * How many live sockets one principal may hold on one scope (#938). A tab holds one per
5061
- * feed (the desk's, and one per open conversation in ticket0's portal), and each socket is
5062
- * work on every post-commit pass, so a principal opening more is a cost on everybody else
5063
- * writing to the scope. Eight covers several tabs; past it a socket is closed `4429`.
5064
- */
5065
- export declare const LIVE_SOCKETS_PER_PRINCIPAL = 8;
5066
5056
  /** The brand only `vouchedWithin` can apply — a literal cannot type-check as one. */
5067
5057
  declare const vouchedBrand: unique symbol;
5068
5058
  /**