@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
@@ -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, WireWalkAudit } 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
  *
@@ -1385,6 +1452,15 @@ export interface ScopedConnectorConnection extends ConnectorConnection {
1385
1452
  * falls back rather than failing a dispatch over a missing file.
1386
1453
  */
1387
1454
  openAttachment(attachmentId: string): Promise<OpenedAttachment | null>;
1455
+ /**
1456
+ * `openAttachment`, with the bytes as a stream that is never held whole (#2514), for a connector
1457
+ * that sends a file on to a provider. Gated the same way, before any byte is read. The sha256 is
1458
+ * checked as the bytes flow, and a mismatch errors the stream before its last chunk is handed on
1459
+ * (see {@link OpenedAttachmentStream}), so a connector that sends what it read must treat a stream
1460
+ * error as "nothing was read", never as a shorter file. A stream it decides not to read is
1461
+ * cancelled (`body.stream.getReader().cancel()`), which releases the stored object at once.
1462
+ */
1463
+ openAttachmentStream(attachmentId: string): Promise<OpenedAttachmentStream | null>;
1388
1464
  /**
1389
1465
  * What this connection may do in the scope this delivery is for (#726 gap 1) —
1390
1466
  * `connectionGrantsInScope`, narrowed to this connection.
@@ -1450,7 +1526,12 @@ export interface ConnectorContext {
1450
1526
  export type ConnectorHandler = (ctx: ConnectorContext, event: DomainEvent) => void | Promise<void>;
1451
1527
  /** Tuning for one connector's egress. */
1452
1528
  export interface ConnectorOptions extends ExecutorRetryPolicy {
1453
- /** Per-request timeout. Default 30s. */
1529
+ /**
1530
+ * Per-request timeout. Default 30s. It bounds the call up to the response headers and a
1531
+ * buffered read of the body. A streamed body (`ConnectorResponse.body`) is bounded by an idle
1532
+ * window instead (#2518, `STREAM_IDLE_TIMEOUT_MS`) and an absolute cap (`STREAM_MAX_DURATION_MS`):
1533
+ * it may take longer than this, as long as bytes keep arriving.
1534
+ */
1454
1535
  timeoutMs?: number;
1455
1536
  /**
1456
1537
  * The provider slug this connector operates (#574 phase 3) — the routing key a
@@ -1701,6 +1782,17 @@ export interface HostAdmin {
1701
1782
  * absent writes through the admin it holds, unattributed to a person.
1702
1783
  */
1703
1784
  attributed?(onBehalfOf: OnBehalfOf): HostAdmin;
1785
+ /**
1786
+ * Write a tenant's role definition (an upsert). Throws `forbidden` (#2447,
1787
+ * `reservedRoleDefinitionRefusal`) for a person's role holding a key reserved to a system
1788
+ * principal, or a system-held role holding a key a person may hold, judged against what the
1789
+ * host's modules reserve and declare and the tenant's other roles (a system-held role's keys
1790
+ * count as reserved). A redefinition is judged against the stored row of its key: a stored
1791
+ * system-held role's keys count as reserved when it is redefined as a person's, and a stored
1792
+ * person's role held by anyone but a system principal cannot become `holder: 'system'`. A key the
1793
+ * host knows nothing about is admitted. A refusal writes nothing, so the stored definition and
1794
+ * every seat of it are left as they were.
1795
+ */
1704
1796
  defineRole(actor: PlatformActorId, tenantId: TenantId, role: RoleDefinition): Promise<void>;
1705
1797
  /**
1706
1798
  * Every role the directory holds, ordered by (tenantId, key).
@@ -2239,6 +2331,13 @@ export interface HostAdmin {
2239
2331
  * while the refusal above is being raced. Staff-only, audited.
2240
2332
  */
2241
2333
  deleteVertical(actor: PlatformActorId, slug: string): Promise<void>;
2334
+ /**
2335
+ * Every period of a slug's ownership (#2501), oldest first: opened by `registerVertical`, closed
2336
+ * by `deleteVertical`, each in that write's transaction. Served for a deleted slug too, which is
2337
+ * the point: a past period bills whoever owned the vertical then. Access-logged (K-24).
2338
+ * Optional, so a host built before it still satisfies `HostAdmin`.
2339
+ */
2340
+ listVerticalOwners?(actor: PlatformActorId, slug: string): Promise<VerticalOwnerPeriod[]>;
2242
2341
  /**
2243
2342
  * Promote a version to a channel (#31 step 2) — the moment a change reaches
2244
2343
  * anyone, and therefore where §4's two human checkpoints belong.
@@ -2401,6 +2500,32 @@ export interface HostAdmin {
2401
2500
  * digest of the served version's migrations (#2349) — one read per upload, never a scan.
2402
2501
  */
2403
2502
  versionMigrations(actor: PlatformActorId, verticalSlug: string, versionId: string): Promise<DeclaredMigration[] | null>;
2503
+ /**
2504
+ * Record what one upload gave the script it went to (RFC wire-signing §7, Q8): the capability
2505
+ * record, written by the uploader from what it built and injected, never declared by the
2506
+ * vertical. It replaces that script's earlier record, so it is always the last upload's. Audited.
2507
+ *
2508
+ * Optional, like the gauge's methods: a host that lacks them records nothing, and the readiness
2509
+ * report reads a deployment with no record as unknown, never as ready.
2510
+ */
2511
+ recordWireAuth?(actor: PlatformActorId, input: DeploymentWireAuthInput): Promise<void>;
2512
+ /**
2513
+ * One page of the stored capability records, by script name: `limit` (required, at most
2514
+ * `LIST_PAGE_MAX`), `cursor` the last script name of the page before, `order`. Confined by `reach`,
2515
+ * which is required: one tenant's verticals (`{ tenantId }`, the verticals it owns now) or the
2516
+ * whole fleet (`{ fleet: true }`), so a reader that forgets to confine itself is refused, never
2517
+ * handed every tenant's deployments. A tenant reach follows the vertical's current owner, resolved
2518
+ * at read time (`DeploymentWireAuthReach`). Optionally one vertical's within that. A bad filter is
2519
+ * `validation_failed` (`assertWireAuthFilter`). Access-logged (K-24). Reached through the host API
2520
+ * only today.
2521
+ */
2522
+ listWireAuth?(actor: PlatformActorId, filter: DeploymentWireAuthFilter): Promise<DeploymentWireAuth[]>;
2523
+ /**
2524
+ * Audit one pass of the fleet walk (RFC wire-signing follow-on 4) as `walkWireAuth`: a person's act,
2525
+ * dry run or applied. Each script the pass changed writes its own `recordWireAuth` row as well, with
2526
+ * its record, in one directory transaction.
2527
+ */
2528
+ recordWireWalk?(actor: PlatformActorId, entry: WireWalkAudit): Promise<void>;
2404
2529
  /**
2405
2530
  * Point a scope's ROUTING at the serving script its data now lives in. Per-scope
2406
2531
  * truth, deliberately not derived from the vertical: rerouting a scope whose DOs
@@ -2555,6 +2680,14 @@ export interface HostAdmin {
2555
2680
  binding: string;
2556
2681
  bytes: number;
2557
2682
  }[]>;
2683
+ /**
2684
+ * A CO-LOCATED scope's attachment bytes (#2501): what its attachment rows sum to
2685
+ * (`ATTACHMENT_BYTES_SQL`). Bytes in the blob store that no row names are not in it. Like
2686
+ * `scopeDatabaseSize` it wakes the scope and is access-logged; for a dispatch vertical the
2687
+ * platform reads it through the vertical's `/internal/attachment-size` instead. Optional, so a
2688
+ * host built before it still satisfies `HostAdmin`.
2689
+ */
2690
+ scopeAttachmentBytes?(actor: PlatformActorId, tenantId: TenantId, scopeId: ScopeId): Promise<number>;
2558
2691
  /**
2559
2692
  * #286's backout: PITR-rewind a scope to a pre-migration bookmark — schema AND
2560
2693
  * data, discarding every write since. Audited (destructive by design). The scope
@@ -2717,6 +2850,17 @@ export interface HostAdmin {
2717
2850
  getTenant(actor: PlatformActorId, tenantId: TenantId): Promise<Tenant | undefined>;
2718
2851
  /** The scope inventory. Ordered by scope_id (ULID = chronological); cursor = scope id. */
2719
2852
  listScopes(actor: PlatformActorId, filter?: ScopeFilter): Promise<Scope[]>;
2853
+ /**
2854
+ * `listScopes` for a fleet-wide pass: the same rows in the same order, except that a row which
2855
+ * does not read as a `Scope` is named in `unreadable` instead of failing the whole list. A
2856
+ * healthy directory answers exactly what `listScopes` does, with `unreadable` empty.
2857
+ *
2858
+ * `listScopes` stays strict: a console or a route showing the directory should fail loudly on
2859
+ * a row it cannot read. A pass over every scope (`runPlatformSweep`) should step over that one
2860
+ * row and say so, which is what this read is for. Optional, so a host that predates it is read
2861
+ * through `listScopes`.
2862
+ */
2863
+ listScopesReadable?(actor: PlatformActorId, filter?: ScopeFilter): Promise<ScopeListing>;
2720
2864
  /**
2721
2865
  * The tenant-store ledger (#301): every platform-minted per-tenant store, optionally
2722
2866
  * narrowed by tenant and/or vertical. The deploy path reads `{ vertical }` to derive
@@ -3404,9 +3548,12 @@ export interface HostAdmin {
3404
3548
  * suspension is an outage, not revenue), and expiry is evaluated at the reading's
3405
3549
  * instant so a lapsed grant reads as lapsed rather than as never-granted.
3406
3550
  *
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.
3551
+ * Computes nothing that needs a data pipeline, so it carries meters 1 and 2 only.
3552
+ * Meter 4 has no number: it needs the cross-tenant order flow. Meter 3 is not
3553
+ * folded into this reading; its parts are read elsewhere: the storage gauge, the
3554
+ * model usage ledger, and the estimated daily request rollup at `/meters/requests`.
3555
+ * Lake rows carry their bytes, but no reader sums them yet. Exact API counts are
3556
+ * not computable: reads emit nothing on the spine. See control-plane.md §5.
3410
3557
  *
3411
3558
  * Nothing is stored: a reading is recomputed per call. D-30 is meter, do not bill,
3412
3559
  * and a persisted running total is the first half of a billing ledger.
@@ -3742,8 +3889,8 @@ export interface HostAdmin {
3742
3889
  recorded: number;
3743
3890
  }>;
3744
3891
  /**
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).
3892
+ * Stored storage samples (#1524) — the latest per scope, or a bounded history,
3893
+ * which includes a reaped scope's kept days (#2515). See `ScopeStorageFilter`. A directory read that wakes no scope. Access-logged (K-24).
3747
3894
  */
3748
3895
  listScopeStorage?(actor: PlatformActorId, filter?: ScopeStorageFilter): Promise<ScopeStorageSample[]>;
3749
3896
  /** Every stored scope's latest storage-read attempt (#1524): the storage phase's due list. Access-logged. */
@@ -3753,6 +3900,49 @@ export interface HostAdmin {
3753
3900
  * `limit` per call, so a backlog drains over passes. Returns how many went. Not audited.
3754
3901
  */
3755
3902
  pruneScopeStorage?(actor: PlatformActorId, limit: number): Promise<number>;
3903
+ /**
3904
+ * The daily request rollup (#2501): record one attempt to read a UTC day's request counts from
3905
+ * the router's datapoints. A successful read replaces the day's rows and marks the day read; a
3906
+ * failed one records only the attempt and its error. Every count is an estimate. Returns how
3907
+ * many rows were written. Not audited, like `recordScopeStorage`: a sweep's own bookkeeping.
3908
+ *
3909
+ * The rollup methods are optional, and the sweep's rollup phase is skipped on a host that lacks
3910
+ * them, so an adapter built before #2501 still satisfies `HostAdmin`.
3911
+ */
3912
+ recordRequestDay?(actor: PlatformActorId, input: RequestDayReadInput): Promise<{
3913
+ recorded: number;
3914
+ }>;
3915
+ /** Stored daily request counts (#2501), every one an estimate. See `RequestDayFilter`. Access-logged (K-24). */
3916
+ listRequestDays?(actor: PlatformActorId, filter?: RequestDayFilter): Promise<RequestDay[]>;
3917
+ /** The rollup's record of each day it tried (#2501): what the phase picks due days by. Access-logged. */
3918
+ listRequestRollupDays?(actor: PlatformActorId, filter?: RequestRollupDayFilter): Promise<RequestRollupDay[]>;
3919
+ /**
3920
+ * Delete day rows older than a retention of `retentionMonths`, oldest first and at most `limit`
3921
+ * per call. `null` deletes nothing (`BILLING_ROLLUP_RETENTION_MONTHS`). Returns how many went.
3922
+ * Not audited, like `pruneScopeStorage`.
3923
+ */
3924
+ pruneRequestDays?(actor: PlatformActorId, limit: number, retentionMonths: number | null): Promise<number>;
3925
+ /**
3926
+ * The daily meter snapshot (#2501): record one attempt at the snapshot of the UTC day of
3927
+ * `input.at`. Without an error it takes the snapshot, in one directory transaction, unless the
3928
+ * day already has one: meters 1 and 2 folded by `foldMeterReading` at `input.at`, one row per
3929
+ * tenant that is not reaped. With an error it records only the failed attempt. Not audited, like
3930
+ * `recordRequestDay`: a sweep's own bookkeeping, and nothing it reads leaves the directory.
3931
+ *
3932
+ * The snapshot methods are optional, and the sweep's snapshot phase is skipped on a host that
3933
+ * lacks them, so an adapter built before #2501's snapshot still satisfies `HostAdmin`.
3934
+ */
3935
+ recordMeterDay?(actor: PlatformActorId, input: MeterDayTakeInput): Promise<MeterDayTakeResult>;
3936
+ /** Stored daily meter snapshots (#2501). See `MeterDayFilter`. Access-logged (K-24). */
3937
+ listMeterDays?(actor: PlatformActorId, filter?: MeterDayFilter): Promise<MeterDay[]>;
3938
+ /** The record of each day a pass tried to snapshot (#2501): what the phase reads its run from. Access-logged. */
3939
+ listMeterDayTakes?(actor: PlatformActorId, filter?: MeterDayTakeFilter): Promise<MeterDayTake[]>;
3940
+ /**
3941
+ * Delete snapshot rows older than a retention of `retentionMonths`, oldest first and at most
3942
+ * `limit` per call. `null` deletes nothing (`BILLING_ROLLUP_RETENTION_MONTHS`). Returns how many
3943
+ * went. Not audited, like `pruneRequestDays`.
3944
+ */
3945
+ pruneMeterDays?(actor: PlatformActorId, limit: number, retentionMonths: number | null): Promise<number>;
3756
3946
  /**
3757
3947
  * A staff verdict on one issue (#1233): resolve, ignore, or reopen. `regressed`
3758
3948
  * is ingest's word and not accepted here. Returns the updated row, or undefined
@@ -3943,6 +4133,15 @@ export interface ProvisionScopeInput {
3943
4133
  name?: string;
3944
4134
  /** Which vertical's deployment executes this scope. Defaults to null. */
3945
4135
  vertical?: string | null;
4136
+ /**
4137
+ * Where `vertical` came from, which decides what it is held to. `'input'` (the default): a
4138
+ * caller named it, and it must be a `verticalSlug`. `'copy'`: it is the stored vertical of a
4139
+ * scope that already exists and this one copies (a snapshot, a sibling), taken as the directory
4140
+ * reads it (any non-empty string), so a scope stored before the grammar was held at provisioning
4141
+ * can still be copied. Platform code sets `'copy'` only with a value it read from the directory;
4142
+ * no request body carries it.
4143
+ */
4144
+ verticalSource?: 'input' | 'copy';
3946
4145
  storageShape?: StorageShape;
3947
4146
  jurisdiction?: Jurisdiction;
3948
4147
  /**
@@ -4027,13 +4226,29 @@ export interface BlobStoreProvisionInput {
4027
4226
  * is what turns "scope/<id>/ is a convention" into "cross-scope keys are unwritable".
4028
4227
  */
4029
4228
  export interface TenantBlobStore {
4030
- put(key: string, body: Uint8Array, opts?: {
4229
+ /**
4230
+ * Write `body` under `key`. A `SizedByteStream` (#2498) is written as it is read, never
4231
+ * collected first, and refused if it carries other than its declared length. The put
4232
+ * resolves only once the whole stream has been read.
4233
+ */
4234
+ put(key: string, body: ByteBody, opts?: {
4031
4235
  contentType?: string;
4032
4236
  }): Promise<void>;
4033
4237
  get(key: string): Promise<{
4034
4238
  body: Uint8Array;
4035
4239
  contentType?: string;
4036
4240
  } | null>;
4241
+ /**
4242
+ * The object under `key` as a stream (#2514), with the size the store holds for it, read as the
4243
+ * consumer reads it and never collected first. Optional, so a store written before it still
4244
+ * satisfies this interface: an open over such a store reads the object with `get` and hands it on
4245
+ * as a stream, which works but holds the object whole.
4246
+ */
4247
+ getStream?(key: string): Promise<{
4248
+ stream: ByteStream;
4249
+ size: number;
4250
+ contentType?: string;
4251
+ } | null>;
4037
4252
  delete(key: string): Promise<void>;
4038
4253
  /** Keys under `prefix` — the GC/ops walk. */
4039
4254
  list(prefix: string): Promise<string[]>;
@@ -4066,6 +4281,31 @@ export declare function attachmentBlobKey(scopeId: string, attachmentId: string)
4066
4281
  * both adapters' `open`, and the extraction job (#1575).
4067
4282
  */
4068
4283
  export declare function attachmentSha256(body: Uint8Array): Promise<string>;
4284
+ /**
4285
+ * Write an upload's bytes to the blob store and answer the record they make (#2498) — the "bytes
4286
+ * first" half of every attachment write, one path for both adapters. The record's fields are
4287
+ * judged before a byte moves, so a record the surface would refuse lands no object. A buffer is
4288
+ * then hashed and written, as before. A stream is hashed and counted while the store reads it, so
4289
+ * it is never held whole; `sha256` is the adapter's running digest, since the kernel has none of
4290
+ * its own. The caller writes the row.
4291
+ *
4292
+ * A streamed write that fails, or whose store answers without reading the stream to its end, has
4293
+ * its object deleted and is refused: no record may witness bytes nobody saw.
4294
+ */
4295
+ export declare function putAttachmentBytes(store: TenantBlobStore, key: string, fields: AttachmentRecordFields, body: ByteBody, sha256: () => IncrementalSha256): Promise<AttachmentRecord>;
4296
+ /**
4297
+ * The bytes of an attachment the scope has already AUTHORIZED, as a stream held to its record (#2514):
4298
+ * the "bytes" half of every streamed open, one path for both adapters, as {@link putAttachmentBytes}
4299
+ * is for the write. The caller checks the read permission first and calls this only once it passed,
4300
+ * so a refused read never reaches the store.
4301
+ *
4302
+ * The length is the record's `size`, which the upload took from the bytes themselves. The store's own
4303
+ * size for the object is held to it before the first byte, so an object that is not the recorded one
4304
+ * is refused up front. The sha256 is checked as the bytes flow ({@link verifiedStream}): a mismatch
4305
+ * errors the stream before its last chunk is handed on. A store without `getStream` is read whole with
4306
+ * `get` and handed on the same way.
4307
+ */
4308
+ export declare function openAttachmentByteStream(store: TenantBlobStore, key: string, record: AttachmentRecord, sha256: () => IncrementalSha256): Promise<OpenedAttachmentStream>;
4069
4309
  /**
4070
4310
  * Who binds an operation, as the §4.3 entitlement gate needs to know it: the owning
4071
4311
  * module, the SKU flag its manifest declares, and the operations that module declares
@@ -4167,7 +4407,13 @@ export interface AttachmentUploadInput {
4167
4407
  filename: string;
4168
4408
  contentType: string;
4169
4409
  visibility: Visibility;
4170
- body: Uint8Array;
4410
+ /**
4411
+ * The bytes: a buffer, or a `SizedByteStream` for a file too large to hold (#2498). A stream
4412
+ * goes to the blob store as it is read; its sha256 and size are taken on the way through, and
4413
+ * the row is written after the object, as for a buffer. Its declared length is the record's
4414
+ * `size`, and a stream that carries a different number of bytes lands nothing.
4415
+ */
4416
+ body: ByteBody;
4171
4417
  }
4172
4418
  /**
4173
4419
  * Input to `ScopeHost.redeemUploadLink`. No `visibility`: the link carries it, as it carries
@@ -4197,6 +4443,18 @@ export interface OpenedAttachment {
4197
4443
  body: Uint8Array;
4198
4444
  contentType: string;
4199
4445
  }
4446
+ /**
4447
+ * An opened attachment whose bytes are a stream (#2514): the metadata fact, and its bytes at the
4448
+ * record's `size`, read as the consumer reads them. The sha256 is checked as they pass, so a
4449
+ * mismatch errors the stream before its last chunk instead of refusing up front: a consumer that
4450
+ * has received all `size` bytes has received bytes that matched the record. One-shot: read it once,
4451
+ * or cancel it, which releases the stored object; a stream that is neither holds it until collected.
4452
+ */
4453
+ export interface OpenedAttachmentStream {
4454
+ record: AttachmentRecord;
4455
+ body: SizedByteStream;
4456
+ contentType: string;
4457
+ }
4200
4458
  /**
4201
4459
  * The attachment surface a host mints per (principal, scope) — `attachmentTargets`
4202
4460
  * finally consumed (#473). Every method is gated INSIDE the platform by the declared
@@ -4213,6 +4471,12 @@ export interface ScopeAttachments {
4213
4471
  list(entity: EntityRef): Promise<AttachmentRecord[]>;
4214
4472
  /** Record + bytes, or null for an id this scope does not know. Gated per entity. */
4215
4473
  open(attachmentId: string): Promise<OpenedAttachment | null>;
4474
+ /**
4475
+ * `open`, with the bytes as a stream that is never held whole (#2514). The same gate, checked
4476
+ * before the store is touched, and the same `null`; the integrity check moves to the stream (see
4477
+ * {@link OpenedAttachmentStream}).
4478
+ */
4479
+ openStream(attachmentId: string): Promise<OpenedAttachmentStream | null>;
4216
4480
  /** Delete row (and event) first, then bytes; returns the removed record, null if unknown. */
4217
4481
  remove(attachmentId: string): Promise<AttachmentRecord | null>;
4218
4482
  /**
@@ -4262,6 +4526,22 @@ export interface ScopeFilter extends ListPage {
4262
4526
  status?: ScopeStatus | ScopeStatus[];
4263
4527
  vertical?: string;
4264
4528
  }
4529
+ /**
4530
+ * A directory row that does not read as a `Scope`. Its ids as stored and the names of the
4531
+ * fields that did not parse, and nothing else of the row: the ids are what an operator needs to
4532
+ * find it, and its contents are not this report's to repeat.
4533
+ */
4534
+ export interface UnreadableScopeRow {
4535
+ scopeId: string;
4536
+ tenantId: string;
4537
+ /** Top-level `Scope` field names that did not parse; `['row']` when the failure names none. */
4538
+ fields: string[];
4539
+ }
4540
+ /** What `HostAdmin.listScopesReadable` answers. */
4541
+ export interface ScopeListing {
4542
+ scopes: Scope[];
4543
+ unreadable: UnreadableScopeRow[];
4544
+ }
4265
4545
  /**
4266
4546
  * Narrow the admin audit trail (control-plane.md §4.4/§4.5). Every field is a
4267
4547
  * conjunctive AND; omitting all of them reads the whole log, which is why `limit`
@@ -4486,6 +4766,16 @@ export interface OpsFailureInput {
4486
4766
  message: string;
4487
4767
  /** The upstream provider's trace reference, when the message carried one. */
4488
4768
  reference?: string | null;
4769
+ /**
4770
+ * #2540: the failure's own text, when `message` is only what the request was answered. A row
4771
+ * filed under a tenant is read back by that tenant, so a host given `detail` on one writes it on
4772
+ * a second row with no tenant under the same `reference`, which only staff read, and counts the
4773
+ * failure once: the issue takes `detail` as its last message, owned as the platform's (the row it
4774
+ * copies), so a subject erasure reaches it on an id match. Ignored on a row with no tenant, whose
4775
+ * `message` is staff's already. A tenant-readable row never carries an upstream trace handle: a
4776
+ * writer keeps one only at the start of this text (`withUpstreamReference`; `referenceInText`).
4777
+ */
4778
+ detail?: string | null;
4489
4779
  }
4490
4780
  /** How long a recorded copy move owns its pending entries before a sweep may settle them (#1722). */
4491
4781
  export declare const SCOPE_COPY_LEASE_MS: number;
@@ -4549,6 +4839,12 @@ export interface OpsFailureFilter {
4549
4839
  fingerprint?: string;
4550
4840
  /** Exact match — the lookup a CI log's `reference = <id>` line lands on. */
4551
4841
  reference?: string;
4842
+ /**
4843
+ * #2540: with `reference`, also every pair whose row with no tenant names `reference = <reference>`
4844
+ * in its text (an upstream trace handle, which a withheld failure keeps only there), both rows of
4845
+ * it. Staff's search: the text it matches is staff's, so a confined read never sets it.
4846
+ */
4847
+ referenceInText?: boolean;
4552
4848
  since?: string;
4553
4849
  until?: string;
4554
4850
  limit?: number;
@@ -5175,8 +5471,14 @@ export interface ScopeHost {
5175
5471
  * class as `drainDue`/`migrateScope`; the invocation itself is attributed to the
5176
5472
  * system actor. A single schedule's failure is reported, never thrown, so one bad
5177
5473
  * operation cannot stop the others on the scope.
5474
+ *
5475
+ * `tick` (#2517) carries what this sweep tick already did to the scope before this call: a
5476
+ * sweep that runs several modules' schedules on one scope with no drain between them passes the
5477
+ * sum of the earlier calls' `purgeRequests`, so a purge head the cap refuses because those
5478
+ * purges filled the queue is deferred rather than failed (`runPurgePass`). Optional; absent
5479
+ * means none.
5178
5480
  */
5179
- runDueSchedules(moduleId: ModuleId, tenantId: TenantId, scopeId: ScopeId): Promise<ScheduleRunReport>;
5481
+ runDueSchedules(moduleId: ModuleId, tenantId: TenantId, scopeId: ScopeId, tick?: ScheduleTick): Promise<ScheduleRunReport>;
5180
5482
  /**
5181
5483
  * The declared freshness expectations, per module (#1232). OPTIONAL and
5182
5484
  * feature-detected like `registeredSchedules` is by the sweep: a pre-#1232