@substrat-run/kernel 0.159.0 → 0.161.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 (95) hide show
  1. package/dist/billing-retention.d.ts +46 -0
  2. package/dist/billing-retention.d.ts.map +1 -0
  3. package/dist/billing-retention.js +78 -0
  4. package/dist/billing-retention.js.map +1 -0
  5. package/dist/byte-stream.d.ts +142 -0
  6. package/dist/byte-stream.d.ts.map +1 -0
  7. package/dist/byte-stream.js +274 -0
  8. package/dist/byte-stream.js.map +1 -0
  9. package/dist/connection-landings.d.ts +15 -3
  10. package/dist/connection-landings.d.ts.map +1 -1
  11. package/dist/connection-landings.js +10 -2
  12. package/dist/connection-landings.js.map +1 -1
  13. package/dist/deadline-fetch.d.ts +34 -0
  14. package/dist/deadline-fetch.d.ts.map +1 -0
  15. package/dist/deadline-fetch.js +231 -0
  16. package/dist/deadline-fetch.js.map +1 -0
  17. package/dist/deployment-wire-auth.d.ts +125 -0
  18. package/dist/deployment-wire-auth.d.ts.map +1 -0
  19. package/dist/deployment-wire-auth.js +161 -0
  20. package/dist/deployment-wire-auth.js.map +1 -0
  21. package/dist/entity-trash.d.ts +65 -8
  22. package/dist/entity-trash.d.ts.map +1 -1
  23. package/dist/entity-trash.js +80 -12
  24. package/dist/entity-trash.js.map +1 -1
  25. package/dist/export-break.d.ts +6 -0
  26. package/dist/export-break.d.ts.map +1 -1
  27. package/dist/export-break.js +11 -0
  28. package/dist/export-break.js.map +1 -1
  29. package/dist/index.d.ts +19 -10
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +17 -8
  32. package/dist/index.js.map +1 -1
  33. package/dist/meter-days.d.ts +107 -0
  34. package/dist/meter-days.d.ts.map +1 -0
  35. package/dist/meter-days.js +230 -0
  36. package/dist/meter-days.js.map +1 -0
  37. package/dist/meters.d.ts +19 -1
  38. package/dist/meters.d.ts.map +1 -1
  39. package/dist/meters.js +0 -0
  40. package/dist/meters.js.map +1 -1
  41. package/dist/ops-failure-reference.d.ts +43 -0
  42. package/dist/ops-failure-reference.d.ts.map +1 -0
  43. package/dist/ops-failure-reference.js +42 -0
  44. package/dist/ops-failure-reference.js.map +1 -0
  45. package/dist/platform-request-cap.d.ts +9 -0
  46. package/dist/platform-request-cap.d.ts.map +1 -0
  47. package/dist/platform-request-cap.js +42 -0
  48. package/dist/platform-request-cap.js.map +1 -0
  49. package/dist/platform-sweep.d.ts +187 -7
  50. package/dist/platform-sweep.d.ts.map +1 -1
  51. package/dist/platform-sweep.js +388 -45
  52. package/dist/platform-sweep.js.map +1 -1
  53. package/dist/promote-review.d.ts +6 -0
  54. package/dist/promote-review.d.ts.map +1 -1
  55. package/dist/promote-review.js +9 -0
  56. package/dist/promote-review.js.map +1 -1
  57. package/dist/request-rollup.d.ts +161 -0
  58. package/dist/request-rollup.d.ts.map +1 -0
  59. package/dist/request-rollup.js +273 -0
  60. package/dist/request-rollup.js.map +1 -0
  61. package/dist/reserved-roles.d.ts +192 -4
  62. package/dist/reserved-roles.d.ts.map +1 -1
  63. package/dist/reserved-roles.js +314 -2
  64. package/dist/reserved-roles.js.map +1 -1
  65. package/dist/schedule-state.d.ts +5 -0
  66. package/dist/schedule-state.d.ts.map +1 -1
  67. package/dist/scope-host.d.ts +317 -15
  68. package/dist/scope-host.d.ts.map +1 -1
  69. package/dist/scope-host.js +93 -2
  70. package/dist/scope-host.js.map +1 -1
  71. package/dist/scope-lifecycle.d.ts +7 -0
  72. package/dist/scope-lifecycle.d.ts.map +1 -1
  73. package/dist/scope-lifecycle.js +7 -0
  74. package/dist/scope-lifecycle.js.map +1 -1
  75. package/dist/scope-record.d.ts +16 -5
  76. package/dist/scope-record.d.ts.map +1 -1
  77. package/dist/scope-record.js +72 -7
  78. package/dist/scope-record.js.map +1 -1
  79. package/dist/spine-restore.d.ts +7 -3
  80. package/dist/spine-restore.d.ts.map +1 -1
  81. package/dist/spine-restore.js +14 -3
  82. package/dist/spine-restore.js.map +1 -1
  83. package/dist/storage-gauge.d.ts +47 -13
  84. package/dist/storage-gauge.d.ts.map +1 -1
  85. package/dist/storage-gauge.js +84 -27
  86. package/dist/storage-gauge.js.map +1 -1
  87. package/dist/subject-redaction.d.ts +9 -3
  88. package/dist/subject-redaction.d.ts.map +1 -1
  89. package/dist/subject-redaction.js +23 -12
  90. package/dist/subject-redaction.js.map +1 -1
  91. package/dist/vertical-owners.d.ts +69 -0
  92. package/dist/vertical-owners.d.ts.map +1 -0
  93. package/dist/vertical-owners.js +108 -0
  94. package/dist/vertical-owners.js.map +1 -0
  95. package/package.json +2 -2
@@ -21,13 +21,22 @@ import { reservedKeysOf } from '@substrat-run/contracts';
21
21
  * admitted only when its stored holder is `system`. A legacy row with no holder keeps the
22
22
  * old key-only behavior until its definition is written again.
23
23
  *
24
- * Never asked on a provisioning seat or the owner hand-over, and nothing already held is revoked:
25
- * a seat that exists keeps working whatever a later engine declares.
24
+ * A person's door also refuses a role whose stored holder is `system` (#2447), whatever this host
25
+ * knows: the holder a role definition carries is the reservation delivered with the role, so a
26
+ * host that registers no module (and so reserves nothing) still keeps a system-held role from a
27
+ * person. The provisioning owner seat and the owner hand-over are person doors too (#2447).
28
+ *
29
+ * Nothing already held is revoked: a seat that exists keeps working whatever a later engine
30
+ * declares. A refusal is of the write it was asked for, and writes nothing.
26
31
  *
27
32
  * The person's refusal is also `canAssign`'s, which is the bound on taking a role away as well as
28
33
  * on giving it, so it is worded for both: no person's bound covers such a role.
29
34
  */
30
35
  export function reservedRoleRefusal(role, reserved, door) {
36
+ if (door === 'person' && role.holder === 'system') {
37
+ return (`role '${role.key}' is declared holder: 'system', a role for a system principal: no person's bound covers it, to ` +
38
+ `give the role or to take it back (K-55)`);
39
+ }
31
40
  const held = role.permissions.filter((p) => reserved.has(p));
32
41
  if (held.length === 0)
33
42
  return null;
@@ -48,6 +57,304 @@ export function reservedRoleRefusal(role, reserved, door) {
48
57
  return (`role '${role.key}' holds ${keys}, reserved to a system principal, beside ${others.join(', ')}: a role carries ` +
49
58
  `a reserved key only when every key it holds is one (a system-held role, K-55)`);
50
59
  }
60
+ /**
61
+ * Why `role` may not be DEFINED for a tenant whose roles are stored as `tenantRoles`, or null (#2447):
62
+ * the write a role definition makes, judged before it is made, so a role that passed a door when
63
+ * it was assigned cannot be widened afterwards with a key no person may hold. `tenantRoles` is
64
+ * what the host stores for the tenant now, the definition this one replaces included; `seated`
65
+ * says whether anyone but a system principal holds a live seat in the role's key, whether or not a
66
+ * definition of it is stored
67
+ * (`SCOPE_SEATED_ROLES_SQL`, `TENANT_SEATED_ROLES_SQL`).
68
+ *
69
+ * The keys judged reserved are the host's, plus every key one of the tenant's system-held roles
70
+ * holds: K-55 lets a system-held role hold reserved keys only, so its keys are reserved, and the
71
+ * stored holder (#2444) is how a host that registers no modules learns the reservation at all. A
72
+ * key the host's own modules declare unmarked is a person's, whatever a stored role says.
73
+ *
74
+ * - **A first definition** of a key: a person's role (holder omitted or `person`) carrying a
75
+ * reserved key is refused, and so is a system-held role carrying a key a person may hold (one
76
+ * the host's modules declare unmarked, or one a person's role of the tenant holds).
77
+ * - **A redefinition** is judged as that new definition, against the stored roles, so a key added
78
+ * to a role whose seats were made through a person's door meets the person's rule.
79
+ * - **A stored system-held role redefined as a person's** is judged as a person's role with the
80
+ * stored role's keys counted as reserved: the stored holder is the evidence, and a redefinition
81
+ * does not erase it.
82
+ * - **A system-held definition of a key anyone but a system principal holds a seat in** is refused
83
+ * unless a system-held definition is stored for it. What kind of principal holds a seat is not
84
+ * recorded, so a seat made before any definition, under a person's definition, or under a
85
+ * person's definition a projection since dropped may be a person's, and relabelling the role
86
+ * would make it a system principal's. Taking the seats back first, or defining a new key, is the
87
+ * way. A system-held role a release dropped is the exception: its tombstone (#2531) is passed in
88
+ * `tenantRoles` as the stored system-held definition (`reservedRoleSetRefusal`), so adding it back
89
+ * is judged as if it had stayed defined. The seats decide for a role stored before the holder was recorded (#2480: no holder) too:
90
+ * it may be declared `holder: 'system'` only while nobody but a system principal holds a seat in
91
+ * it, since an upgrade admitted beside such a seat would let a later system-held definition add
92
+ * keys to it.
93
+ *
94
+ * **A key the host knows nothing about is admitted, deliberately (fail-open).** A host judges only
95
+ * the reservations of modules it knows and of the tenant's system-held roles. Refusing every key it
96
+ * cannot place would refuse every role a module-less host is given; the push (`substrat push`, the
97
+ * registry boundary) is where the vertical's whole surface is judged. So a key reserved only
98
+ * through a schedule's `permissions`, which no system-held role of the tenant holds, is not caught
99
+ * on a host that does not register its module (the control plane verifying a pushed registry's
100
+ * marks is #2446).
101
+ *
102
+ * A refusal writes nothing, and so revokes nothing: a seat of the role as it was stored keeps
103
+ * working. A definition is never refused for a key it takes out, only for what it still holds.
104
+ */
105
+ export function reservedRoleDefinitionRefusal(role, host, tenantRoles, seated = false) {
106
+ return definitionRefusal(role, host, tenantRoles, seated)?.refusal ?? null;
107
+ }
108
+ /**
109
+ * `reservedRoleDefinitionRefusal` with why it refused (#2555): `seated`, a system-held definition of a
110
+ * key someone holds a seat in with no system-held definition stored; `keys`, a key the role may not hold.
111
+ */
112
+ function definitionRefusal(role, host, tenantRoles, seated) {
113
+ const stored = tenantRoles.find((r) => r.key === role.key);
114
+ const others = tenantRoles.filter((r) => r.key !== role.key);
115
+ const personKey = (p) => host.declared.has(p) && !host.reserved.has(p);
116
+ const bySystemRole = new Map();
117
+ for (const r of others)
118
+ if (r.holder === 'system')
119
+ for (const p of r.permissions)
120
+ if (!bySystemRole.has(p))
121
+ bySystemRole.set(p, `the system-held role '${r.key}'`);
122
+ if (role.holder === 'system') {
123
+ // Judged against the seats of the key, whether or not a definition is stored: a projection can
124
+ // drop a role's row and leave its seats live, and a later definition must not relabel a seat
125
+ // made under a person's definition. A dropped SYSTEM-held row is no relabelling: its tombstone
126
+ // arrives here as `stored` (#2531, `storedDefinitionOf`), so its re-add passes this check.
127
+ // A row stored before the holder was recorded (#2480) is no exception: an upgrade admitted beside
128
+ // a person's seat would leave a system-held row a later definition widens unjudged by its seats.
129
+ if (stored?.holder !== 'system' && seated) {
130
+ return {
131
+ reason: 'seated',
132
+ refusal: `role '${role.key}' is held by a principal (${storedAs(stored)}), so it cannot be declared holder: 'system': what kind ` +
133
+ `of principal holds a seat is not recorded, so the seat may be a person\'s. Take that seat back first, wherever it is ` +
134
+ `held (a scope, or the tenant; a host principal\'s seat can be given again after), keep the role defined across ` +
135
+ `releases, or define the system-held role under a new key (K-55)`,
136
+ };
137
+ }
138
+ const personsKeys = new Map();
139
+ for (const r of others)
140
+ if (r.holder !== 'system')
141
+ for (const p of r.permissions)
142
+ if (!personsKeys.has(p))
143
+ personsKeys.set(p, r.key);
144
+ const offences = role.permissions.flatMap((p) => {
145
+ if (host.reserved.has(p))
146
+ return [];
147
+ if (host.declared.has(p))
148
+ return [`${p} (declared for a person by a module this host registers)`];
149
+ const holder = personsKeys.get(p);
150
+ return holder ? [`${p} (held by the person's role '${holder}')`] : [];
151
+ });
152
+ if (offences.length === 0)
153
+ return null;
154
+ return {
155
+ reason: 'keys',
156
+ refusal: `role '${role.key}' is declared holder: 'system' but holds ${offences.join(', ')}: a system-held role holds only ` +
157
+ `keys reserved to a system principal (K-55)`,
158
+ };
159
+ }
160
+ // The stored system-held definition this one replaces is evidence too: its keys are reserved.
161
+ // A tombstone is no row a role listing shows (#2531), so the refusal says what it is: the role was
162
+ // defined system-held, and has since been dropped.
163
+ const evidence = stored && DROPPED.has(stored) ? 'its definition as a system-held role, since dropped' : 'its stored system-held definition';
164
+ if (stored?.holder === 'system')
165
+ for (const p of stored.permissions)
166
+ if (!bySystemRole.has(p))
167
+ bySystemRole.set(p, evidence);
168
+ const held = role.permissions.flatMap((p) => {
169
+ if (host.reserved.has(p))
170
+ return [`${p} (${RESERVED_BY})`];
171
+ if (personKey(p))
172
+ return [];
173
+ const by = bySystemRole.get(p);
174
+ return by ? [`${p} (held by ${by})`] : [];
175
+ });
176
+ if (held.length === 0)
177
+ return null;
178
+ return {
179
+ reason: 'keys',
180
+ refusal: `role '${role.key}' is a person's role and would hold ${held.join(', ')}, reserved to a system principal: take the key ` +
181
+ `out, or declare a role made only of reserved keys holder: 'system' (K-55)`,
182
+ };
183
+ }
184
+ /** How the seated-key refusal names the stored row of the key, so it says only what is true of it. */
185
+ function storedAs(stored) {
186
+ if (!stored)
187
+ return 'with no definition stored';
188
+ if (stored.holder === undefined)
189
+ return 'stored with no holder, from before holders were recorded (#2480)';
190
+ return "stored as a person's role";
191
+ }
192
+ /**
193
+ * The definition a key's stored row is judged as (#2531): its live row, or else a tombstone the
194
+ * projection left when it dropped a SYSTEM-held role. Such a tombstone counts as the stored
195
+ * system-held definition it was, in both branches: a re-add as system-held is not refused for a
196
+ * seat, and a re-add as a person's counts its keys as reserved. That is parity with keeping the
197
+ * role defined across releases, not proof the seat is a host principal's: the platform's door can
198
+ * seat a person in a system-held role whether its row is live or dropped. A tombstone of a person's
199
+ * role, or of a row with no holder, is no evidence of anything a system principal holds, so the key
200
+ * is judged as having no definition stored, as before.
201
+ */
202
+ function storedDefinitionOf(stored, key) {
203
+ const live = stored?.roles.find((r) => r.key === key);
204
+ if (live)
205
+ return live;
206
+ const found = stored?.dropped?.find((r) => r.key === key && r.holder === 'system');
207
+ if (!found)
208
+ return undefined;
209
+ // A copy, so the mark is this one judgement's and never the caller's object, which it may pass
210
+ // again as a live role.
211
+ const tomb = { ...found };
212
+ DROPPED.add(tomb);
213
+ return tomb;
214
+ }
215
+ /** The copies of tombstones `storedDefinitionOf` handed on as a stored definition, so a refusal can name them as dropped. */
216
+ const DROPPED = new WeakSet();
217
+ /**
218
+ * `reservedRoleDefinitionRefusal` over a whole role set defined at once (a provision's or a
219
+ * restore's projection, which replaces the tenant's roles in a scope): each role judged against the
220
+ * rest of the set and the definition of its own key stored there now (`stored`; a system-held
221
+ * tombstone counts, `storedDefinitionOf`), with its seats. The first refusal, or null.
222
+ */
223
+ export function reservedRoleSetRefusal(roles, host, stored) {
224
+ return firstRefusedRole(roles, host, stored)?.refusal ?? null;
225
+ }
226
+ /**
227
+ * `reservedRoleSetRefusal`'s walk: the first role of the set refused, with the refusal, or null.
228
+ * `judged` narrows which roles are asked about; every role of the set stays their context.
229
+ */
230
+ function firstRefusedRole(roles, host, stored, judged = () => true) {
231
+ for (const role of roles) {
232
+ if (!judged(role))
233
+ continue;
234
+ const own = storedDefinitionOf(stored, role.key);
235
+ const tenantRoles = [...roles.filter((r) => r.key !== role.key), ...(own ? [own] : [])];
236
+ const refused = definitionRefusal(role, host, tenantRoles, stored?.seated.has(role.key) ?? false);
237
+ if (refused)
238
+ return { key: role.key, ...refused };
239
+ }
240
+ return null;
241
+ }
242
+ /**
243
+ * #2555: why a dump may not be loaded into a scope of a host the control plane runs (`restoreScope`,
244
+ * `importScope`), or null. The load brings the dump's scope-level seats, and the roles that apply to
245
+ * them are the tenant's roles as the directory stores them NOW (`roles`). So that set is judged as a
246
+ * restore's projection is (`reservedRoleSetRefusal`), against the dump's own role rows and seats for
247
+ * the tenant it was captured from (`dumpRoleState`). A seat the dump holds in a role the directory
248
+ * has since made system-held is refused, unless the dump stores that role system-held itself. A dump
249
+ * with no role rows (a pure-SQLite scope file, or a scope that read its roles over RPC) says nothing
250
+ * about the definition its seats were made under, so such a seat is judged as a person's, the rule's
251
+ * reading of a seat whose holder is not recorded. A scope holding a seat in a system-held role
252
+ * therefore cannot be restored from its own export on a host whose dump carries no role rows.
253
+ *
254
+ * Only the roles the dump seats or stores are asked about, so a directory role the dump has no part
255
+ * in never refuses a load (the directory's own doors judge it); the whole set stays their context.
256
+ *
257
+ * Asked before anything is replaced, so a refused load moves nothing. The answer is one of two fixed
258
+ * sentences naming the role key only: the rule's own wording is kept out of it, since it is read by
259
+ * whoever sent the dump. The second is chosen from the rule's reason, not from the dump's shape: the
260
+ * seat rule refused, and the dump carries no definition of the role to show its seats were made as a
261
+ * system principal's. A refusal over the keys the tenant's definition holds takes the first.
262
+ */
263
+ export function dumpRoleRefusal(roles, host, dump, now) {
264
+ // #2531: the dump's tombstones come with it (`dumpRoleState`), so the walk reads a system-held one as
265
+ // the stored definition it was (`storedDefinitionOf`), and a role the dump keeps only as a tombstone
266
+ // is one it defines: judged, and answered as defined rather than as having no definition.
267
+ const stored = dumpRoleState(dump.tables, dump.tenantId, now);
268
+ const inDump = (key) => stored.roles.some((r) => r.key === key) || (stored.dropped ?? []).some((r) => r.key === key);
269
+ const refused = firstRefusedRole(roles, host, stored, (r) => stored.seated.has(r.key) || inDump(r.key));
270
+ if (!refused)
271
+ return null;
272
+ if (refused.reason === 'seated' && !inDump(refused.key)) {
273
+ return (`restore refused: the dump seats role '${refused.key}' but carries no definition of it, so its seats cannot be told ` +
274
+ `from a person's, and the tenant now defines the role for a system principal (K-55); nothing was loaded`);
275
+ }
276
+ return `restore refused: role '${refused.key}', which the dump seats or defines, cannot be applied as the tenant defines it now (K-55); nothing was loaded`;
277
+ }
278
+ /**
279
+ * #2446: the reservations a pushed registry's rows mark — `reserved`, every key marked
280
+ * `holder: 'system'`; `declared`, every key it lists. The push boundary holds those marks to the
281
+ * module declarations shipped beside them (`pushedModuleRegistryProblems`), so they are what the
282
+ * incoming version's modules reserve and declare, the reservation its reconcile judges with.
283
+ */
284
+ export function registryReservations(registry) {
285
+ return {
286
+ reserved: new Set(registry.permissions.filter((p) => p.holder === 'system').map((p) => p.key)),
287
+ declared: new Set(registry.permissions.map((p) => p.key)),
288
+ };
289
+ }
290
+ /**
291
+ * #2446: why a release's role set would be refused where a scope stores `state`, or null: the
292
+ * question that scope's reconcile asks (`reservedRoleSetRefusal`, with the incoming version's
293
+ * reservations), asked before a promote moves it. A promote that would hold a seated scope's
294
+ * reconcile is refused instead.
295
+ */
296
+ export function releaseRoleSetRefusal(registry, state) {
297
+ return reservedRoleSetRefusal(registry.roles, registryReservations(registry), {
298
+ roles: state.roles,
299
+ seated: new Set(state.seated),
300
+ ...(state.dropped ? { dropped: state.dropped } : {}),
301
+ });
302
+ }
303
+ /**
304
+ * #2446: whether a release's role set can be refused by any scope's stored state, so its promote
305
+ * must ask the scopes it moves. A system-held role meets the seat rule and the stored definitions
306
+ * (`reservedRoleDefinitionRefusal`). A person's role is judged against stored state only for a key
307
+ * its registry does not declare: every declared key is a reserved one, refused at push, or a
308
+ * person's, which no stored row overrides. A release with neither asks no scope.
309
+ */
310
+ export function releaseRolesAskScopes(registry) {
311
+ const declared = new Set(registry.permissions.map((p) => p.key));
312
+ return registry.roles.some((r) => r.holder === 'system' || r.permissions.some((p) => !declared.has(p)));
313
+ }
314
+ /**
315
+ * #2447: the role keys a scope's own tuples seat anyone but a system principal in, live now — what
316
+ * a role set defined on the scope is judged against. One parameter: now (ISO text).
317
+ */
318
+ export const SCOPE_SEATED_ROLES_SQL = "SELECT DISTINCT substr(relation, 6) AS role_key FROM _substrat_tuples WHERE relation LIKE 'role:%' AND subject NOT LIKE 'system:%' AND revoked_at IS NULL AND (expires_at IS NULL OR expires_at > ?)";
319
+ /**
320
+ * #2447: what a scope dump stores for a tenant's roles, and the role keys anyone but a system
321
+ * principal holds a live scope-level seat in there — `SCOPE_SEATED_ROLES_SQL`'s reading, over a dump's
322
+ * rows instead of a table. A dump's projected tenant-level tuples are not seats here: the repair a
323
+ * restore runs projects none, so they do not survive it, and the tenant's own seats are the
324
+ * directory's. A restore judges the role set its repair defines against it before it imports the dump.
325
+ */
326
+ export function dumpRoleState(tables, tenantId, now) {
327
+ const read = (name) => {
328
+ const t = tables.find((x) => x.name === name);
329
+ return t ? t.rows.map((r) => Object.fromEntries(t.columns.map((c, i) => [c, r[i]]))) : [];
330
+ };
331
+ const live = (r) => r.revoked_at == null && (r.expires_at == null || String(r.expires_at) > now);
332
+ const shapeOf = (r) => ({
333
+ key: String(r.role_key),
334
+ permissions: JSON.parse(String(r.permissions)),
335
+ ...(r.holder === 'person' || r.holder === 'system' ? { holder: r.holder } : {}),
336
+ });
337
+ const tenantRows = read('_substrat_roles').filter((r) => r.tenant_id === tenantId);
338
+ const roles = tenantRows.filter((r) => r.revoked_at == null).map(shapeOf);
339
+ // #2531: a dropped role's tombstone travels with the dump, as the evidence it is in the scope.
340
+ const dropped = tenantRows.filter((r) => r.revoked_at != null).map(shapeOf);
341
+ const seats = read('_substrat_tuples');
342
+ const seated = new Set(seats
343
+ .filter((r) => String(r.relation).startsWith('role:') && !String(r.subject).startsWith('system:') && live(r))
344
+ .map((r) => String(r.relation).slice('role:'.length)));
345
+ return { roles, seated, dropped };
346
+ }
347
+ /**
348
+ * #2447: the scope statuses whose seats count as held when a role definition is judged: every one
349
+ * but `reaped` (whose storage is gone), a scope archived straight from `provisioning` included: it
350
+ * can hold a seat (the platform's door seats into a provisioning scope), and unarchive brings it back.
351
+ * Each adapter reads such a scope without creating storage it never had, and where it cannot, fails
352
+ * closed. An archived scope comes back on unarchive with its seats, so
353
+ * a definition judged without them would relabel those seats; both adapters read this one list.
354
+ */
355
+ export const SEAT_HOLDING_SCOPE_STATUSES = ['provisioning', 'active', 'suspended', 'archiving', 'archived'];
356
+ /** #2447: `SCOPE_SEATED_ROLES_SQL` for a tenant's tenant-level tuples. Parameters: tenantId, now. */
357
+ export const TENANT_SEATED_ROLES_SQL = "SELECT DISTINCT substr(relation, 6) AS role_key FROM _substrat_tenant_tuples WHERE tenant_id = ? AND relation LIKE 'role:%' AND subject NOT LIKE 'system:%' AND revoked_at IS NULL AND (expires_at IS NULL OR expires_at > ?)";
51
358
  /**
52
359
  * Why `permissions` may not be granted directly to a principal, an org or a connection, or null
53
360
  * (#2430): a raw grant (`HostAdmin.grant`, `grantToOrg`, `grantEntityShape`, `ctx.grant`) names a
@@ -91,6 +398,11 @@ export function noteReservedKeys(reserved, manifest) {
91
398
  for (const key of reservedKeysOf([{ manifest: { id: manifest.id, permissions: manifest.permissions ?? [] } }]).keys())
92
399
  reserved.add(key);
93
400
  }
401
+ /** #2447: add every key `manifest` declares, marked or not, to a host's `declared` set (`HostReservations`). */
402
+ export function noteDeclaredKeys(declared, manifest) {
403
+ for (const p of manifest.permissions ?? [])
404
+ declared.add(p.key);
405
+ }
94
406
  /**
95
407
  * A host given its vertical's `permissions` refuses to register a module that list leaves out
96
408
  * (#2430). Every check `lint:permissions` and `substrat push` make reads that list, so a module
@@ -1 +1 @@
1
- {"version":3,"file":"reserved-roles.js","sourceRoot":"","sources":["../src/reserved-roles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAA0B,MAAM,yBAAyB,CAAC;AAEjF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAAmF,EACnF,QAA6B,EAC7B,IAA2B;IAE3B,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,OAAO,CACL,SAAS,IAAI,CAAC,GAAG,WAAW,IAAI,yEAAyE;YACzG,gCAAgC,WAAW,GAAG,CAC/C,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAChE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,6EAA6E;QAC7E,0EAA0E;QAC1E,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACpD,OAAO,SAAS,IAAI,CAAC,GAAG,WAAW,IAAI,gIAAgI,CAAC;QAC1K,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,CACL,SAAS,IAAI,CAAC,GAAG,WAAW,IAAI,4CAA4C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB;QAChH,+EAA+E,CAChF,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAAC,WAA8B,EAAE,QAA6B;IAChG,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACxD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,8FAA8F,WAAW,GAAG,CAAC;AACxI,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAClC,MAAyE,EACzE,QAA6B;IAE7B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,oBAAoB,CAAC,KAAK,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QAClE,IAAI,OAAO;YAAE,OAAO,6BAA6B,KAAK,CAAC,UAAU,KAAK,OAAO,EAAE,CAAC;IAClF,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,WAAW,GAAG,iIAAiI,CAAC;AAEtJ;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAqB,EAAE,QAA0B;IAChF,KAAK,MAAM,GAAG,IAAI,cAAc,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAC3I,CAAC;AAeD;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,WAA4C,EAAE,QAAgB;IACjG,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,KAAK,QAAQ,CAAC;QAAE,OAAO;IACxF,MAAM,IAAI,KAAK,CACb,mBAAmB,QAAQ,oFAAoF;QAC7G,GAAG,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,WAAW,8BAA8B;QACxG,mGAAmG;QACnG,wEAAwE,CAC3E,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"reserved-roles.js","sourceRoot":"","sources":["../src/reserved-roles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAA0B,MAAM,yBAAyB,CAAC;AAEjF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAAe,EACf,QAA6B,EAC7B,IAA2B;IAE3B,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAClD,OAAO,CACL,SAAS,IAAI,CAAC,GAAG,iGAAiG;YAClH,yCAAyC,CAC1C,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,OAAO,CACL,SAAS,IAAI,CAAC,GAAG,WAAW,IAAI,yEAAyE;YACzG,gCAAgC,WAAW,GAAG,CAC/C,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAChE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,6EAA6E;QAC7E,0EAA0E;QAC1E,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACpD,OAAO,SAAS,IAAI,CAAC,GAAG,WAAW,IAAI,gIAAgI,CAAC;QAC1K,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,CACL,SAAS,IAAI,CAAC,GAAG,WAAW,IAAI,4CAA4C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB;QAChH,+EAA+E,CAChF,CAAC;AACJ,CAAC;AAmBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,MAAM,UAAU,6BAA6B,CAC3C,IAAe,EACf,IAAsB,EACtB,WAAiC,EACjC,MAAM,GAAG,KAAK;IAEd,OAAO,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,OAAO,IAAI,IAAI,CAAC;AAC7E,CAAC;AAED;;;GAGG;AACH,SAAS,iBAAiB,CACxB,IAAe,EACf,IAAsB,EACtB,WAAiC,EACjC,MAAe;IAEf,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3D,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC;IAC7D,MAAM,SAAS,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC/E,MAAM,YAAY,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC/C,KAAK,MAAM,CAAC,IAAI,MAAM;QAAE,IAAI,CAAC,CAAC,MAAM,KAAK,QAAQ;YAAE,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,WAAW;gBAAE,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;oBAAE,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,yBAAyB,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;IACnK,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC7B,+FAA+F;QAC/F,6FAA6F;QAC7F,+FAA+F;QAC/F,2FAA2F;QAC3F,kGAAkG;QAClG,iGAAiG;QACjG,IAAI,MAAM,EAAE,MAAM,KAAK,QAAQ,IAAI,MAAM,EAAE,CAAC;YAC1C,OAAO;gBACL,MAAM,EAAE,QAAQ;gBAChB,OAAO,EACL,SAAS,IAAI,CAAC,GAAG,6BAA6B,QAAQ,CAAC,MAAM,CAAC,0DAA0D;oBACxH,uHAAuH;oBACvH,iHAAiH;oBACjH,iEAAiE;aACpE,CAAC;QACJ,CAAC;QACD,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;QAC9C,KAAK,MAAM,CAAC,IAAI,MAAM;YAAE,IAAI,CAAC,CAAC,MAAM,KAAK,QAAQ;gBAAE,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,WAAW;oBAAE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;wBAAE,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;QACrI,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;YAC9C,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;gBAAE,OAAO,EAAE,CAAC;YACpC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;gBAAE,OAAO,CAAC,GAAG,CAAC,0DAA0D,CAAC,CAAC;YAClG,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAClC,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,gCAAgC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACxE,CAAC,CAAC,CAAC;QACH,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACvC,OAAO;YACL,MAAM,EAAE,MAAM;YACd,OAAO,EACL,SAAS,IAAI,CAAC,GAAG,4CAA4C,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,kCAAkC;gBAClH,4CAA4C;SAC/C,CAAC;IACJ,CAAC;IACD,8FAA8F;IAC9F,mGAAmG;IACnG,mDAAmD;IACnD,MAAM,QAAQ,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,qDAAqD,CAAC,CAAC,CAAC,mCAAmC,CAAC;IAC7I,IAAI,MAAM,EAAE,MAAM,KAAK,QAAQ;QAAE,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,WAAW;YAAE,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;gBAAE,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC7H,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;QAC1C,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,KAAK,WAAW,GAAG,CAAC,CAAC;QAC3D,IAAI,SAAS,CAAC,CAAC,CAAC;YAAE,OAAO,EAAE,CAAC;QAC5B,MAAM,EAAE,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC/B,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5C,CAAC,CAAC,CAAC;IACH,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,OAAO;QACL,MAAM,EAAE,MAAM;QACd,OAAO,EACL,SAAS,IAAI,CAAC,GAAG,uCAAuC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,iDAAiD;YACxH,2EAA2E;KAC9E,CAAC;AACJ,CAAC;AAED,sGAAsG;AACtG,SAAS,QAAQ,CAAC,MAA6B;IAC7C,IAAI,CAAC,MAAM;QAAE,OAAO,2BAA2B,CAAC;IAChD,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,kEAAkE,CAAC;IAC3G,OAAO,2BAA2B,CAAC;AACrC,CAAC;AAeD;;;;;;;;;GASG;AACH,SAAS,kBAAkB,CAAC,MAA+B,EAAE,GAAW;IACtE,MAAM,IAAI,GAAG,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;IACtD,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,KAAK,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC;IACnF,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,+FAA+F;IAC/F,wBAAwB;IACxB,MAAM,IAAI,GAAc,EAAE,GAAG,KAAK,EAAE,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAClB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,6HAA6H;AAC7H,MAAM,OAAO,GAAG,IAAI,OAAO,EAAa,CAAC;AAEzC;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAA2B,EAAE,IAAsB,EAAE,MAAoB;IAC9G,OAAO,gBAAgB,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,OAAO,IAAI,IAAI,CAAC;AAChE,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CACvB,KAA2B,EAC3B,IAAsB,EACtB,MAAoB,EACpB,MAAM,GAAiC,GAAG,EAAE,CAAC,IAAI;IAEjD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;YAAE,SAAS;QAC5B,MAAM,GAAG,GAAG,kBAAkB,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QACjD,MAAM,WAAW,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACxF,MAAM,OAAO,GAAG,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC;QAClG,IAAI,OAAO;YAAE,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;IACpD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,eAAe,CAC7B,KAA2B,EAC3B,IAAsB,EACtB,IAAwD,EACxD,GAAW;IAEX,sGAAsG;IACtG,qGAAqG;IACrG,0FAA0F;IAC1F,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;IAC7H,MAAM,OAAO,GAAG,gBAAgB,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACxG,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,IAAI,OAAO,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACxD,OAAO,CACL,yCAAyC,OAAO,CAAC,GAAG,iEAAiE;YACrH,wGAAwG,CACzG,CAAC;IACJ,CAAC;IACD,OAAO,0BAA0B,OAAO,CAAC,GAAG,+GAA+G,CAAC;AAC9J,CAAC;AAeD;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAwE;IAC3G,OAAO;QACL,QAAQ,EAAE,IAAI,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC9F,QAAQ,EAAE,IAAI,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;KAC1D,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CACnC,QAAqG,EACrG,KAAgB;IAEhB,OAAO,sBAAsB,CAAC,QAAQ,CAAC,KAAK,EAAE,oBAAoB,CAAC,QAAQ,CAAC,EAAE;QAC5E,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,MAAM,EAAE,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;QAC7B,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACrD,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAkF;IACtH,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACjE,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1G,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GACjC,sMAAsM,CAAC;AASzM;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,MAA4B,EAAE,QAAgB,EAAE,GAAW;IACvF,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE;QAC5B,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QAC9C,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAA4B,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACvH,CAAC,CAAC;IACF,MAAM,IAAI,GAAG,CAAC,CAA0B,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,UAAU,IAAI,IAAI,IAAI,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC;IAC1H,MAAM,OAAO,GAAG,CAAC,CAA0B,EAAa,EAAE,CAAC,CAAC;QAC1D,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;QACvB,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAa;QAC1D,GAAG,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAA6B,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACvG,CAAC,CAAC;IACH,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC;IACnF,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC1E,+FAA+F;IAC/F,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC5E,MAAM,KAAK,GAAG,IAAI,CAAC,kBAAkB,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,IAAI,GAAG,CACpB,KAAK;SACF,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;SAC5G,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CACxD,CAAC;IACF,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AACpC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,cAAc,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,CAAU,CAAC;AAErH,qGAAqG;AACrG,MAAM,CAAC,MAAM,uBAAuB,GAClC,+NAA+N,CAAC;AAElO;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAAC,WAA8B,EAAE,QAA6B;IAChG,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACxD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,8FAA8F,WAAW,GAAG,CAAC;AACxI,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAClC,MAAyE,EACzE,QAA6B;IAE7B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,oBAAoB,CAAC,KAAK,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QAClE,IAAI,OAAO;YAAE,OAAO,6BAA6B,KAAK,CAAC,UAAU,KAAK,OAAO,EAAE,CAAC;IAClF,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,WAAW,GAAG,iIAAiI,CAAC;AAEtJ;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAqB,EAAE,QAA0B;IAChF,KAAK,MAAM,GAAG,IAAI,cAAc,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAC3I,CAAC;AAED,gHAAgH;AAChH,MAAM,UAAU,gBAAgB,CAAC,QAAqB,EAAE,QAA0B;IAChF,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,WAAW,IAAI,EAAE;QAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAClE,CAAC;AAeD;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,WAA4C,EAAE,QAAgB;IACjG,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,KAAK,QAAQ,CAAC;QAAE,OAAO;IACxF,MAAM,IAAI,KAAK,CACb,mBAAmB,QAAQ,oFAAoF;QAC7G,GAAG,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,WAAW,8BAA8B;QACxG,mGAAmG;QACnG,wEAAwE,CAC3E,CAAC;AACJ,CAAC"}
@@ -92,5 +92,10 @@ export interface ScheduleSweepReport {
92
92
  * `ScheduleRunReport.platformRequests`. Absent when none did.
93
93
  */
94
94
  platformRequests?: number;
95
+ /**
96
+ * #2517: purge runs deferred to the next tick because the tick's earlier purges filled the queue,
97
+ * summed from each pass's `ScheduleRunReport.deferred`. Already counted in `skipped`. Absent when none.
98
+ */
99
+ deferred?: number;
95
100
  }
96
101
  //# sourceMappingURL=schedule-state.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schedule-state.d.ts","sourceRoot":"","sources":["../src/schedule-state.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,WAAW,CAAC;AAEzD;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,48EAqC9B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,6FACsD,CAAC;AAE7F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,sBAAsB,QAclC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,kEAAkE;IAClE,MAAM,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B"}
1
+ {"version":3,"file":"schedule-state.d.ts","sourceRoot":"","sources":["../src/schedule-state.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,WAAW,CAAC;AAEzD;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,48EAqC9B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,6FACsD,CAAC;AAE7F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,sBAAsB,QAclC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,kEAAkE;IAClE,MAAM,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB"}