@substrat-run/kernel 0.158.0 → 0.160.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 +102 -0
  6. package/dist/byte-stream.d.ts.map +1 -0
  7. package/dist/byte-stream.js +153 -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 +82 -0
  18. package/dist/deployment-wire-auth.d.ts.map +1 -0
  19. package/dist/deployment-wire-auth.js +150 -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 +18 -9
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +16 -7
  32. package/dist/index.js.map +1 -1
  33. package/dist/invocation-line.d.ts +3 -2
  34. package/dist/invocation-line.d.ts.map +1 -1
  35. package/dist/invocation-line.js +2 -0
  36. package/dist/invocation-line.js.map +1 -1
  37. package/dist/meter-days.d.ts +107 -0
  38. package/dist/meter-days.d.ts.map +1 -0
  39. package/dist/meter-days.js +230 -0
  40. package/dist/meter-days.js.map +1 -0
  41. package/dist/meters.d.ts +19 -1
  42. package/dist/meters.d.ts.map +1 -1
  43. package/dist/meters.js +0 -0
  44. package/dist/meters.js.map +1 -1
  45. package/dist/ops-failure-reference.d.ts +31 -0
  46. package/dist/ops-failure-reference.d.ts.map +1 -0
  47. package/dist/ops-failure-reference.js +32 -0
  48. package/dist/ops-failure-reference.js.map +1 -0
  49. package/dist/platform-request-cap.d.ts +9 -0
  50. package/dist/platform-request-cap.d.ts.map +1 -0
  51. package/dist/platform-request-cap.js +42 -0
  52. package/dist/platform-request-cap.js.map +1 -0
  53. package/dist/platform-sweep.d.ts +170 -7
  54. package/dist/platform-sweep.d.ts.map +1 -1
  55. package/dist/platform-sweep.js +375 -45
  56. package/dist/platform-sweep.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 +157 -4
  62. package/dist/reserved-roles.d.ts.map +1 -1
  63. package/dist/reserved-roles.js +216 -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 +260 -15
  68. package/dist/scope-host.d.ts.map +1 -1
  69. package/dist/scope-host.js +53 -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 +24 -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
@@ -6,17 +6,21 @@ import type { DeliveryRefusal } from './delivery-refusal.js';
6
6
  import type { ScopeRoleHolder } from './scope-role-admin.js';
7
7
  import type { ScopeCopyBackfillResult, SubjectErasureFence } from './scope-copy-ledger.js';
8
8
  import type { VerticalScopeStore } from './vertical-scope-stores.js';
9
+ import type { DeploymentWireAuthFilter, DeploymentWireAuthInput } from './deployment-wire-auth.js';
9
10
  import type { StoreDriverHoldMode, StoreDriverRebuildFailure, StoreDriverRebuildRecord, StoreDriverReleaseRecord, StoreDriverRolloutAction, StoreDriverRolloutRecord, StoreDriverRolloutState, StoreDriverRolloutTarget, StoreDriverState } from './store-driver-releases.js';
10
11
  import type { SubjectRedactionCounts } from './subject-redaction.js';
11
- 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, ConnectionBindingAudit, CopyMarkAudit, OrphanSweepAudit, 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, ScopeDumpInput, SubjectShredReceipt, ScopeQueryResult, ScopeId, ScopeStatus, ScopeTable, DenialFilter, DenialSummary, RefusalFilter, RefusalRecord, PermissionDenial, Coverage, BeginImpersonationInput, ImpersonationFilter, ImpersonationSession, ImpersonationSessionId, ScopeTablePage, StorageShape, Tenant, TenantId, TenantRole, TenantStoreHandle, AttachmentRecord, UploadLinkView, 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';
12
+ 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, ConnectionBindingAudit, CopyMarkAudit, OrphanSweepAudit, 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, MeterDay, MeterDayTake, VerticalOwnerPeriod, ScopeStorageSample, RequestDay, RequestRollupDay, 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, DeploymentWireAuth, RouteTarget, DirectoryDump, IdentityMembership, PrincipalId, ResolvedIdentity, RoleAssignment, RoleDefinition, QueryScopeInput, ReadScopeTableInput, Scope, ScopeDump, ScopeDumpInput, SubjectShredReceipt, ScopeQueryResult, ScopeId, ScopeStatus, ScopeTable, DenialFilter, DenialSummary, RefusalFilter, RefusalRecord, PermissionDenial, Coverage, BeginImpersonationInput, ImpersonationFilter, ImpersonationSession, ImpersonationSessionId, ScopeTablePage, StorageShape, Tenant, TenantId, TenantRole, TenantStoreHandle, AttachmentRecord, UploadLinkView, 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';
12
13
  import type { ConnectionUseOutcome } from './connector-calls.js';
14
+ import { type ByteBody, type ByteStream, type IncrementalSha256, type SizedByteStream } from './byte-stream.js';
13
15
  import type { CapabilityVerbs } from './capability.js';
14
16
  import type { AttachmentVerbs } from './upload-link.js';
15
17
  import type { AuditedOperationRef, AuditedOperationRow } from './audit-outcome.js';
16
- import { type EntityStateName } from '@substrat-run/contracts';
18
+ import { type AttachmentRecordFields, type EntityStateName } from '@substrat-run/contracts';
17
19
  import type { ModelUsageFilter, ModelUsageInput, ModelUsageWindow } from './model-usage.js';
18
20
  import type { FindingPruneReport } from './findings.js';
19
21
  import type { ScopeStorageAttempt, ScopeStorageFilter, ScopeStorageReadingInput } from './storage-gauge.js';
22
+ import type { RequestDayFilter, RequestDayReadInput, RequestRollupDayFilter } from './request-rollup.js';
23
+ import type { MeterDayFilter, MeterDayTakeFilter, MeterDayTakeInput, MeterDayTakeResult } from './meter-days.js';
20
24
  import type { SealedSecret } from './secret-box.js';
21
25
  import type { OnSubjectErased } from './module-erasure.js';
22
26
  import type { SystemSwitchReassert, SystemSwitchReassertOptions, SystemSwitchRecordFilter } from './system-switch-record.js';
@@ -1197,11 +1201,29 @@ export interface ScheduleRunReport {
1197
1201
  * no such drain (D-40): there the count is reported, and the requests wait for the control
1198
1202
  * plane's sweep. Whatever is not counted waits for the next drain, as it always did. Absent
1199
1203
  * when the count is zero, and from a host that predates the field. A purge horizon's runs
1200
- * count what the host can see: on the node host every purge is an invoke and counts like
1201
- * one; on the Durable Object host the purges run inside the scope, so only the deliveries
1202
- * their events route to the platform are counted, not the requests the purges make themselves.
1204
+ * count the same on both hosts: each committed purge's `ctx.requestPlatform` calls (on the
1205
+ * SQLite host every purge is an invoke and counts like one; on the Durable Object host the
1206
+ * scope reports them as `PurgePass.platformRequests`), plus, on the Durable Object host, the
1207
+ * deliveries their events route to the platform. A purge that threw adds nothing.
1203
1208
  */
1204
1209
  platformRequests?: number;
1210
+ /**
1211
+ * #2517: the part of `platformRequests` the purge horizons' runs enqueued. A sweep running
1212
+ * another module's schedules on the same scope in the same tick passes the running sum on
1213
+ * (`ScheduleTick.earlierPurgeRequests`). Absent when zero, and from a host that predates it.
1214
+ */
1215
+ purgeRequests?: number;
1216
+ /**
1217
+ * #2517: purge runs whose head waits for the next tick because the tick's earlier purges filled
1218
+ * the queue (`PurgePass.deferred`). Each is also in `skipped`, never `fired`, and its run is
1219
+ * `skipped`: it ran nothing and moved no cadence row. Absent when none.
1220
+ */
1221
+ deferred?: number;
1222
+ }
1223
+ /** #2517: what a sweep tick already did to a scope before a `runDueSchedules` call. */
1224
+ export interface ScheduleTick {
1225
+ /** Platform requests the purge runs of the tick's earlier calls on this scope enqueued (their `purgeRequests`). */
1226
+ earlierPurgeRequests?: number;
1205
1227
  }
1206
1228
  /**
1207
1229
  * The web-standard fetch surface, structurally typed.
@@ -1233,8 +1255,21 @@ export interface FetchLike {
1233
1255
  * installs, so no suite in this repo sees the difference; the Fortnox consent
1234
1256
  * callback shipped green and failed every hosted round that way (#1291). Closing
1235
1257
  * over the global here means the receiver is never in play, anywhere downstream.
1258
+ *
1259
+ * A `SizedByteStream` body (#2498) is converted by `fetchLikeOf`, which this is built from.
1236
1260
  */
1237
1261
  export declare const globalFetch: FetchLike;
1262
+ /**
1263
+ * A runtime `fetch` (the global, a service binding's, a test's stand-in) as a `FetchLike`
1264
+ * (#2498): the one place a `SizedByteStream` body becomes a request the runtime can send, as
1265
+ * `knownLengthInit` builds it. The runtime takes no such value: handed one as it is, a `fetch`
1266
+ * sends its string form, `"[object Object]"`, and answers as if nothing were wrong. So
1267
+ * `globalFetch` is built from this, and both hosts pass the `fetch` they are given through it,
1268
+ * as `runPlatformSweep` does, so a sized body reaches no runtime `fetch` unconverted whichever
1269
+ * one was injected. Wrapping a `FetchLike` that is already one is harmless: a converted body is
1270
+ * no longer a `SizedByteStream`.
1271
+ */
1272
+ export declare function fetchLikeOf(runtimeFetch: (input: string, init?: never) => Promise<ConnectorResponse>): FetchLike;
1238
1273
  /**
1239
1274
  * The host's clock (#812) — what `ctx.now()` reads.
1240
1275
  *
@@ -1274,8 +1309,15 @@ export interface ConnectorRequestInit {
1274
1309
  * string cannot carry without corrupting the file. Web `fetch` accepts both, so
1275
1310
  * this only widens the declared surface — the adapter passes it straight
1276
1311
  * through.
1312
+ *
1313
+ * A {@link SizedByteStream} as well (#2498), for a body too large to hold in memory. The
1314
+ * length is part of the value because a provider wants a `Content-Length`, and a stream
1315
+ * carries none. The runtime cannot take one as it is, so it is converted by `fetchLikeOf`:
1316
+ * `globalFetch` is built from it, and both hosts and `runPlatformSweep` pass the `fetch` they
1317
+ * are given through it. A runtime `fetch` handed straight to a connector is made a
1318
+ * `FetchLike` with `fetchLikeOf` too, never by a cast.
1277
1319
  */
1278
- body?: string | Uint8Array;
1320
+ body?: string | Uint8Array | SizedByteStream;
1279
1321
  signal?: unknown;
1280
1322
  }
1281
1323
  export interface ConnectorResponse {
@@ -1290,6 +1332,31 @@ export interface ConnectorResponse {
1290
1332
  * only widens the structural surface the adapter passes straight through.
1291
1333
  */
1292
1334
  arrayBuffer(): Promise<ArrayBuffer>;
1335
+ /**
1336
+ * The body as a stream (#2498), for a provider file too large to hold: read it chunk by chunk,
1337
+ * or hand it on to `upload` as a `SizedByteStream`. `null` for a response with no body, as on
1338
+ * a web `Response`, which every adapter's `fetch` returns.
1339
+ *
1340
+ * The stream carries the body as `fetch` delivers it: DECODED. A response sent with a
1341
+ * `Content-Encoding` (gzip, br) is decompressed on the way, while its `Content-Length` still
1342
+ * counts the compressed bytes, so that header is the stream's length only when the response
1343
+ * has no `Content-Encoding`. Otherwise take the length from the provider's own record of the
1344
+ * file (its item metadata); a stream sized by the wrong number is refused, not landed.
1345
+ *
1346
+ * The stream is bounded by IDLENESS, not by total transfer time (#2518). A connection's `fetch`
1347
+ * holds the connector's `timeoutMs` (default 30 s) over the call up to the headers and over a
1348
+ * buffered read, and still holds it while `body` is only looked at or never read. From the first
1349
+ * read of the stream the deadline hands over: it errors (`TimeoutError`) when the provider sends
1350
+ * no byte for `STREAM_IDLE_TIMEOUT_MS` (an empty chunk is not a byte), or when
1351
+ * `STREAM_MAX_DURATION_MS` has passed in all. A transfer that keeps flowing completes within
1352
+ * that. A stalled or endless one errors, the connection is released, and an upload reading it
1353
+ * lands no object and no row.
1354
+ *
1355
+ * OPTIONAL for the reason `headers` is: a hand-built stand-in is an object literal, and most
1356
+ * connectors never read a stream. A caller that needs one falls back to `arrayBuffer()` when it
1357
+ * is absent. Read a body once, by one of these.
1358
+ */
1359
+ readonly body?: ByteStream | null;
1293
1360
  /**
1294
1361
  * The response headers, when the runtime behind this seam has them.
1295
1362
  *
@@ -1450,7 +1517,12 @@ export interface ConnectorContext {
1450
1517
  export type ConnectorHandler = (ctx: ConnectorContext, event: DomainEvent) => void | Promise<void>;
1451
1518
  /** Tuning for one connector's egress. */
1452
1519
  export interface ConnectorOptions extends ExecutorRetryPolicy {
1453
- /** Per-request timeout. Default 30s. */
1520
+ /**
1521
+ * Per-request timeout. Default 30s. It bounds the call up to the response headers and a
1522
+ * buffered read of the body. A streamed body (`ConnectorResponse.body`) is bounded by an idle
1523
+ * window instead (#2518, `STREAM_IDLE_TIMEOUT_MS`) and an absolute cap (`STREAM_MAX_DURATION_MS`):
1524
+ * it may take longer than this, as long as bytes keep arriving.
1525
+ */
1454
1526
  timeoutMs?: number;
1455
1527
  /**
1456
1528
  * The provider slug this connector operates (#574 phase 3) — the routing key a
@@ -1701,6 +1773,17 @@ export interface HostAdmin {
1701
1773
  * absent writes through the admin it holds, unattributed to a person.
1702
1774
  */
1703
1775
  attributed?(onBehalfOf: OnBehalfOf): HostAdmin;
1776
+ /**
1777
+ * Write a tenant's role definition (an upsert). Throws `forbidden` (#2447,
1778
+ * `reservedRoleDefinitionRefusal`) for a person's role holding a key reserved to a system
1779
+ * principal, or a system-held role holding a key a person may hold, judged against what the
1780
+ * host's modules reserve and declare and the tenant's other roles (a system-held role's keys
1781
+ * count as reserved). A redefinition is judged against the stored row of its key: a stored
1782
+ * system-held role's keys count as reserved when it is redefined as a person's, and a stored
1783
+ * person's role held by anyone but a system principal cannot become `holder: 'system'`. A key the
1784
+ * host knows nothing about is admitted. A refusal writes nothing, so the stored definition and
1785
+ * every seat of it are left as they were.
1786
+ */
1704
1787
  defineRole(actor: PlatformActorId, tenantId: TenantId, role: RoleDefinition): Promise<void>;
1705
1788
  /**
1706
1789
  * Every role the directory holds, ordered by (tenantId, key).
@@ -2239,6 +2322,13 @@ export interface HostAdmin {
2239
2322
  * while the refusal above is being raced. Staff-only, audited.
2240
2323
  */
2241
2324
  deleteVertical(actor: PlatformActorId, slug: string): Promise<void>;
2325
+ /**
2326
+ * Every period of a slug's ownership (#2501), oldest first: opened by `registerVertical`, closed
2327
+ * by `deleteVertical`, each in that write's transaction. Served for a deleted slug too, which is
2328
+ * the point: a past period bills whoever owned the vertical then. Access-logged (K-24).
2329
+ * Optional, so a host built before it still satisfies `HostAdmin`.
2330
+ */
2331
+ listVerticalOwners?(actor: PlatformActorId, slug: string): Promise<VerticalOwnerPeriod[]>;
2242
2332
  /**
2243
2333
  * Promote a version to a channel (#31 step 2) — the moment a change reaches
2244
2334
  * anyone, and therefore where §4's two human checkpoints belong.
@@ -2401,6 +2491,26 @@ export interface HostAdmin {
2401
2491
  * digest of the served version's migrations (#2349) — one read per upload, never a scan.
2402
2492
  */
2403
2493
  versionMigrations(actor: PlatformActorId, verticalSlug: string, versionId: string): Promise<DeclaredMigration[] | null>;
2494
+ /**
2495
+ * Record what one upload gave the script it went to (RFC wire-signing §7, Q8): the capability
2496
+ * record, written by the uploader from what it built and injected, never declared by the
2497
+ * vertical. It replaces that script's earlier record, so it is always the last upload's. Audited.
2498
+ *
2499
+ * Optional, like the gauge's methods: a host that lacks them records nothing, and the readiness
2500
+ * report reads a deployment with no record as unknown, never as ready.
2501
+ */
2502
+ recordWireAuth?(actor: PlatformActorId, input: DeploymentWireAuthInput): Promise<void>;
2503
+ /**
2504
+ * One page of the stored capability records, by script name: `limit` (required, at most
2505
+ * `LIST_PAGE_MAX`), `cursor` the last script name of the page before, `order`. Confined by `reach`,
2506
+ * which is required: one tenant's verticals (`{ tenantId }`, the verticals it owns now) or the
2507
+ * whole fleet (`{ fleet: true }`), so a reader that forgets to confine itself is refused, never
2508
+ * handed every tenant's deployments. A tenant reach follows the vertical's current owner, resolved
2509
+ * at read time (`DeploymentWireAuthReach`). Optionally one vertical's within that. A bad filter is
2510
+ * `validation_failed` (`assertWireAuthFilter`). Access-logged (K-24). Reached through the host API
2511
+ * only today.
2512
+ */
2513
+ listWireAuth?(actor: PlatformActorId, filter: DeploymentWireAuthFilter): Promise<DeploymentWireAuth[]>;
2404
2514
  /**
2405
2515
  * Point a scope's ROUTING at the serving script its data now lives in. Per-scope
2406
2516
  * truth, deliberately not derived from the vertical: rerouting a scope whose DOs
@@ -2555,6 +2665,14 @@ export interface HostAdmin {
2555
2665
  binding: string;
2556
2666
  bytes: number;
2557
2667
  }[]>;
2668
+ /**
2669
+ * A CO-LOCATED scope's attachment bytes (#2501): what its attachment rows sum to
2670
+ * (`ATTACHMENT_BYTES_SQL`). Bytes in the blob store that no row names are not in it. Like
2671
+ * `scopeDatabaseSize` it wakes the scope and is access-logged; for a dispatch vertical the
2672
+ * platform reads it through the vertical's `/internal/attachment-size` instead. Optional, so a
2673
+ * host built before it still satisfies `HostAdmin`.
2674
+ */
2675
+ scopeAttachmentBytes?(actor: PlatformActorId, tenantId: TenantId, scopeId: ScopeId): Promise<number>;
2558
2676
  /**
2559
2677
  * #286's backout: PITR-rewind a scope to a pre-migration bookmark — schema AND
2560
2678
  * data, discarding every write since. Audited (destructive by design). The scope
@@ -2717,6 +2835,17 @@ export interface HostAdmin {
2717
2835
  getTenant(actor: PlatformActorId, tenantId: TenantId): Promise<Tenant | undefined>;
2718
2836
  /** The scope inventory. Ordered by scope_id (ULID = chronological); cursor = scope id. */
2719
2837
  listScopes(actor: PlatformActorId, filter?: ScopeFilter): Promise<Scope[]>;
2838
+ /**
2839
+ * `listScopes` for a fleet-wide pass: the same rows in the same order, except that a row which
2840
+ * does not read as a `Scope` is named in `unreadable` instead of failing the whole list. A
2841
+ * healthy directory answers exactly what `listScopes` does, with `unreadable` empty.
2842
+ *
2843
+ * `listScopes` stays strict: a console or a route showing the directory should fail loudly on
2844
+ * a row it cannot read. A pass over every scope (`runPlatformSweep`) should step over that one
2845
+ * row and say so, which is what this read is for. Optional, so a host that predates it is read
2846
+ * through `listScopes`.
2847
+ */
2848
+ listScopesReadable?(actor: PlatformActorId, filter?: ScopeFilter): Promise<ScopeListing>;
2720
2849
  /**
2721
2850
  * The tenant-store ledger (#301): every platform-minted per-tenant store, optionally
2722
2851
  * narrowed by tenant and/or vertical. The deploy path reads `{ vertical }` to derive
@@ -3404,9 +3533,12 @@ export interface HostAdmin {
3404
3533
  * suspension is an outage, not revenue), and expiry is evaluated at the reading's
3405
3534
  * instant so a lapsed grant reads as lapsed rather than as never-granted.
3406
3535
  *
3407
- * Computes nothing that needs a data pipeline. Meters 3 and 4 are absent because
3408
- * they are uncomputable by construction, not because this is a first slice — the
3409
- * per-scope outbox has no cross-tenant fan-in, and reads emit nothing at all.
3536
+ * Computes nothing that needs a data pipeline, so it carries meters 1 and 2 only.
3537
+ * Meter 4 has no number: it needs the cross-tenant order flow. Meter 3 is not
3538
+ * folded into this reading; its parts are read elsewhere: the storage gauge, the
3539
+ * model usage ledger, and the estimated daily request rollup at `/meters/requests`.
3540
+ * Lake rows carry their bytes, but no reader sums them yet. Exact API counts are
3541
+ * not computable: reads emit nothing on the spine. See control-plane.md §5.
3410
3542
  *
3411
3543
  * Nothing is stored: a reading is recomputed per call. D-30 is meter, do not bill,
3412
3544
  * and a persisted running total is the first half of a billing ledger.
@@ -3742,8 +3874,8 @@ export interface HostAdmin {
3742
3874
  recorded: number;
3743
3875
  }>;
3744
3876
  /**
3745
- * Stored storage samples (#1524) — the latest per scope, or a bounded history. See
3746
- * `ScopeStorageFilter`. A directory read that wakes no scope. Access-logged (K-24).
3877
+ * Stored storage samples (#1524) — the latest per scope, or a bounded history,
3878
+ * which includes a reaped scope's kept days (#2515). See `ScopeStorageFilter`. A directory read that wakes no scope. Access-logged (K-24).
3747
3879
  */
3748
3880
  listScopeStorage?(actor: PlatformActorId, filter?: ScopeStorageFilter): Promise<ScopeStorageSample[]>;
3749
3881
  /** Every stored scope's latest storage-read attempt (#1524): the storage phase's due list. Access-logged. */
@@ -3753,6 +3885,49 @@ export interface HostAdmin {
3753
3885
  * `limit` per call, so a backlog drains over passes. Returns how many went. Not audited.
3754
3886
  */
3755
3887
  pruneScopeStorage?(actor: PlatformActorId, limit: number): Promise<number>;
3888
+ /**
3889
+ * The daily request rollup (#2501): record one attempt to read a UTC day's request counts from
3890
+ * the router's datapoints. A successful read replaces the day's rows and marks the day read; a
3891
+ * failed one records only the attempt and its error. Every count is an estimate. Returns how
3892
+ * many rows were written. Not audited, like `recordScopeStorage`: a sweep's own bookkeeping.
3893
+ *
3894
+ * The rollup methods are optional, and the sweep's rollup phase is skipped on a host that lacks
3895
+ * them, so an adapter built before #2501 still satisfies `HostAdmin`.
3896
+ */
3897
+ recordRequestDay?(actor: PlatformActorId, input: RequestDayReadInput): Promise<{
3898
+ recorded: number;
3899
+ }>;
3900
+ /** Stored daily request counts (#2501), every one an estimate. See `RequestDayFilter`. Access-logged (K-24). */
3901
+ listRequestDays?(actor: PlatformActorId, filter?: RequestDayFilter): Promise<RequestDay[]>;
3902
+ /** The rollup's record of each day it tried (#2501): what the phase picks due days by. Access-logged. */
3903
+ listRequestRollupDays?(actor: PlatformActorId, filter?: RequestRollupDayFilter): Promise<RequestRollupDay[]>;
3904
+ /**
3905
+ * Delete day rows older than a retention of `retentionMonths`, oldest first and at most `limit`
3906
+ * per call. `null` deletes nothing (`BILLING_ROLLUP_RETENTION_MONTHS`). Returns how many went.
3907
+ * Not audited, like `pruneScopeStorage`.
3908
+ */
3909
+ pruneRequestDays?(actor: PlatformActorId, limit: number, retentionMonths: number | null): Promise<number>;
3910
+ /**
3911
+ * The daily meter snapshot (#2501): record one attempt at the snapshot of the UTC day of
3912
+ * `input.at`. Without an error it takes the snapshot, in one directory transaction, unless the
3913
+ * day already has one: meters 1 and 2 folded by `foldMeterReading` at `input.at`, one row per
3914
+ * tenant that is not reaped. With an error it records only the failed attempt. Not audited, like
3915
+ * `recordRequestDay`: a sweep's own bookkeeping, and nothing it reads leaves the directory.
3916
+ *
3917
+ * The snapshot methods are optional, and the sweep's snapshot phase is skipped on a host that
3918
+ * lacks them, so an adapter built before #2501's snapshot still satisfies `HostAdmin`.
3919
+ */
3920
+ recordMeterDay?(actor: PlatformActorId, input: MeterDayTakeInput): Promise<MeterDayTakeResult>;
3921
+ /** Stored daily meter snapshots (#2501). See `MeterDayFilter`. Access-logged (K-24). */
3922
+ listMeterDays?(actor: PlatformActorId, filter?: MeterDayFilter): Promise<MeterDay[]>;
3923
+ /** The record of each day a pass tried to snapshot (#2501): what the phase reads its run from. Access-logged. */
3924
+ listMeterDayTakes?(actor: PlatformActorId, filter?: MeterDayTakeFilter): Promise<MeterDayTake[]>;
3925
+ /**
3926
+ * Delete snapshot rows older than a retention of `retentionMonths`, oldest first and at most
3927
+ * `limit` per call. `null` deletes nothing (`BILLING_ROLLUP_RETENTION_MONTHS`). Returns how many
3928
+ * went. Not audited, like `pruneRequestDays`.
3929
+ */
3930
+ pruneMeterDays?(actor: PlatformActorId, limit: number, retentionMonths: number | null): Promise<number>;
3756
3931
  /**
3757
3932
  * A staff verdict on one issue (#1233): resolve, ignore, or reopen. `regressed`
3758
3933
  * is ingest's word and not accepted here. Returns the updated row, or undefined
@@ -3943,6 +4118,15 @@ export interface ProvisionScopeInput {
3943
4118
  name?: string;
3944
4119
  /** Which vertical's deployment executes this scope. Defaults to null. */
3945
4120
  vertical?: string | null;
4121
+ /**
4122
+ * Where `vertical` came from, which decides what it is held to. `'input'` (the default): a
4123
+ * caller named it, and it must be a `verticalSlug`. `'copy'`: it is the stored vertical of a
4124
+ * scope that already exists and this one copies (a snapshot, a sibling), taken as the directory
4125
+ * reads it (any non-empty string), so a scope stored before the grammar was held at provisioning
4126
+ * can still be copied. Platform code sets `'copy'` only with a value it read from the directory;
4127
+ * no request body carries it.
4128
+ */
4129
+ verticalSource?: 'input' | 'copy';
3946
4130
  storageShape?: StorageShape;
3947
4131
  jurisdiction?: Jurisdiction;
3948
4132
  /**
@@ -4027,7 +4211,12 @@ export interface BlobStoreProvisionInput {
4027
4211
  * is what turns "scope/<id>/ is a convention" into "cross-scope keys are unwritable".
4028
4212
  */
4029
4213
  export interface TenantBlobStore {
4030
- put(key: string, body: Uint8Array, opts?: {
4214
+ /**
4215
+ * Write `body` under `key`. A `SizedByteStream` (#2498) is written as it is read, never
4216
+ * collected first, and refused if it carries other than its declared length. The put
4217
+ * resolves only once the whole stream has been read.
4218
+ */
4219
+ put(key: string, body: ByteBody, opts?: {
4031
4220
  contentType?: string;
4032
4221
  }): Promise<void>;
4033
4222
  get(key: string): Promise<{
@@ -4066,6 +4255,18 @@ export declare function attachmentBlobKey(scopeId: string, attachmentId: string)
4066
4255
  * both adapters' `open`, and the extraction job (#1575).
4067
4256
  */
4068
4257
  export declare function attachmentSha256(body: Uint8Array): Promise<string>;
4258
+ /**
4259
+ * Write an upload's bytes to the blob store and answer the record they make (#2498) — the "bytes
4260
+ * first" half of every attachment write, one path for both adapters. The record's fields are
4261
+ * judged before a byte moves, so a record the surface would refuse lands no object. A buffer is
4262
+ * then hashed and written, as before. A stream is hashed and counted while the store reads it, so
4263
+ * it is never held whole; `sha256` is the adapter's running digest, since the kernel has none of
4264
+ * its own. The caller writes the row.
4265
+ *
4266
+ * A streamed write that fails, or whose store answers without reading the stream to its end, has
4267
+ * its object deleted and is refused: no record may witness bytes nobody saw.
4268
+ */
4269
+ export declare function putAttachmentBytes(store: TenantBlobStore, key: string, fields: AttachmentRecordFields, body: ByteBody, sha256: () => IncrementalSha256): Promise<AttachmentRecord>;
4069
4270
  /**
4070
4271
  * Who binds an operation, as the §4.3 entitlement gate needs to know it: the owning
4071
4272
  * module, the SKU flag its manifest declares, and the operations that module declares
@@ -4167,7 +4368,13 @@ export interface AttachmentUploadInput {
4167
4368
  filename: string;
4168
4369
  contentType: string;
4169
4370
  visibility: Visibility;
4170
- body: Uint8Array;
4371
+ /**
4372
+ * The bytes: a buffer, or a `SizedByteStream` for a file too large to hold (#2498). A stream
4373
+ * goes to the blob store as it is read; its sha256 and size are taken on the way through, and
4374
+ * the row is written after the object, as for a buffer. Its declared length is the record's
4375
+ * `size`, and a stream that carries a different number of bytes lands nothing.
4376
+ */
4377
+ body: ByteBody;
4171
4378
  }
4172
4379
  /**
4173
4380
  * Input to `ScopeHost.redeemUploadLink`. No `visibility`: the link carries it, as it carries
@@ -4262,6 +4469,22 @@ export interface ScopeFilter extends ListPage {
4262
4469
  status?: ScopeStatus | ScopeStatus[];
4263
4470
  vertical?: string;
4264
4471
  }
4472
+ /**
4473
+ * A directory row that does not read as a `Scope`. Its ids as stored and the names of the
4474
+ * fields that did not parse, and nothing else of the row: the ids are what an operator needs to
4475
+ * find it, and its contents are not this report's to repeat.
4476
+ */
4477
+ export interface UnreadableScopeRow {
4478
+ scopeId: string;
4479
+ tenantId: string;
4480
+ /** Top-level `Scope` field names that did not parse; `['row']` when the failure names none. */
4481
+ fields: string[];
4482
+ }
4483
+ /** What `HostAdmin.listScopesReadable` answers. */
4484
+ export interface ScopeListing {
4485
+ scopes: Scope[];
4486
+ unreadable: UnreadableScopeRow[];
4487
+ }
4265
4488
  /**
4266
4489
  * Narrow the admin audit trail (control-plane.md §4.4/§4.5). Every field is a
4267
4490
  * conjunctive AND; omitting all of them reads the whole log, which is why `limit`
@@ -4486,6 +4709,16 @@ export interface OpsFailureInput {
4486
4709
  message: string;
4487
4710
  /** The upstream provider's trace reference, when the message carried one. */
4488
4711
  reference?: string | null;
4712
+ /**
4713
+ * #2540: the failure's own text, when `message` is only what the request was answered. A row
4714
+ * filed under a tenant is read back by that tenant, so a host given `detail` on one writes it on
4715
+ * a second row with no tenant under the same `reference`, which only staff read, and counts the
4716
+ * failure once: the issue takes `detail` as its last message, owned as the platform's (the row it
4717
+ * copies), so a subject erasure reaches it on an id match. Ignored on a row with no tenant, whose
4718
+ * `message` is staff's already. A tenant-readable row never carries an upstream trace handle: a
4719
+ * writer keeps one only at the start of this text (`withUpstreamReference`; `referenceInText`).
4720
+ */
4721
+ detail?: string | null;
4489
4722
  }
4490
4723
  /** How long a recorded copy move owns its pending entries before a sweep may settle them (#1722). */
4491
4724
  export declare const SCOPE_COPY_LEASE_MS: number;
@@ -4549,6 +4782,12 @@ export interface OpsFailureFilter {
4549
4782
  fingerprint?: string;
4550
4783
  /** Exact match — the lookup a CI log's `reference = <id>` line lands on. */
4551
4784
  reference?: string;
4785
+ /**
4786
+ * #2540: with `reference`, also every pair whose row with no tenant names `reference = <reference>`
4787
+ * in its text (an upstream trace handle, which a withheld failure keeps only there), both rows of
4788
+ * it. Staff's search: the text it matches is staff's, so a confined read never sets it.
4789
+ */
4790
+ referenceInText?: boolean;
4552
4791
  since?: string;
4553
4792
  until?: string;
4554
4793
  limit?: number;
@@ -5175,8 +5414,14 @@ export interface ScopeHost {
5175
5414
  * class as `drainDue`/`migrateScope`; the invocation itself is attributed to the
5176
5415
  * system actor. A single schedule's failure is reported, never thrown, so one bad
5177
5416
  * operation cannot stop the others on the scope.
5417
+ *
5418
+ * `tick` (#2517) carries what this sweep tick already did to the scope before this call: a
5419
+ * sweep that runs several modules' schedules on one scope with no drain between them passes the
5420
+ * sum of the earlier calls' `purgeRequests`, so a purge head the cap refuses because those
5421
+ * purges filled the queue is deferred rather than failed (`runPurgePass`). Optional; absent
5422
+ * means none.
5178
5423
  */
5179
- runDueSchedules(moduleId: ModuleId, tenantId: TenantId, scopeId: ScopeId): Promise<ScheduleRunReport>;
5424
+ runDueSchedules(moduleId: ModuleId, tenantId: TenantId, scopeId: ScopeId, tick?: ScheduleTick): Promise<ScheduleRunReport>;
5180
5425
  /**
5181
5426
  * The declared freshness expectations, per module (#1232). OPTIONAL and
5182
5427
  * feature-detected like `registeredSchedules` is by the sweep: a pre-#1232