@substrat-run/control-plane-api 0.152.0 → 0.154.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.
package/dist/api.d.ts CHANGED
@@ -17,6 +17,7 @@ import { type DoNamespaceReader } from './do-namespaces.js';
17
17
  import type { DirectoryBackupStore, ScopeBackupStore } from './backups.js';
18
18
  import { type LakeQueryEngine } from './lake-gateway.js';
19
19
  import { type CustomHostnameProvisioner } from './custom-hostnames.js';
20
+ import { type SocialRelayOptions } from './social-relay.js';
20
21
  /**
21
22
  * What one provider can answer about a live connection (#605) — the seam behind
22
23
  * `POST /tenants/:t/connections/:id/verify` and `GET …/activity`.
@@ -372,6 +373,13 @@ export interface ControlPlaneApiOptions {
372
373
  * self-host / dev shape, where there is no CF-for-SaaS zone).
373
374
  */
374
375
  provisionHostname?: CustomHostnameProvisioner;
376
+ /**
377
+ * The platform's social relay (#1544, `social-relay.ts`): how an Auth Server install is given
378
+ * its own client there. When present, a hostname of such an install becoming active
379
+ * reconciles that install, and the two staff routes under `social-relay` can reconcile one
380
+ * install or all of them. Absent ⇒ nothing here ever calls the relay.
381
+ */
382
+ socialRelay?: SocialRelayOptions;
375
383
  /**
376
384
  * The platform's base domains — the wildcard-covered zones a PLATFORM hostname is
377
385
  * minted under (`substrat.run`, `global.substrat.run`, …). A bind AT or UNDER one of
package/dist/api.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
package/dist/api.js CHANGED
@@ -1,14 +1,14 @@
1
1
  import { PREVIEW_CONNECTIONS_REFUSAL } from './connection-relay.js';
2
2
  import { resolveObservabilityWindow } from './observability-window.js';
3
3
  import { Hono } from 'hono';
4
- import { permissionKey, parseHostname, withLabel, RESERVED_LABEL_SEPARATOR, adminAction, lakeEventsInput, ownerTransferInput, memberInviteInput, memberRoleInput, ASSET_PART_PREFIX, assetHash, STORE_DRIVERS, STORE_RELEASE_MAX_BYTES, channelName, connectLinkId, connectionActivity, connectionActivitySource, connectionCredential, connectionCertificate, connectionFilter, connectionHealthState, connectionProvider, connectorDispatchKind, PROVISION_SIBLING_KIND, ARCHIVE_SCOPE_KIND, PROVISION_TENANT_KIND, SET_ENTITLEMENTS_KIND, MODEL_USAGE_KIND, SWEEP_RUNS_KIND, toConnectionHealthEntry, CONNECTION_EXPIRY_WARNING_DAYS, CONNECTION_STALE_DAYS, connectionProbe, createTenantInput, entitlementGrantInput, hostname as hostnameSchema, hostnameRegion, hostnameStatus, identityLink, errorCode, issueStatus, issueStatusInput, FINDINGS_LIMIT_DEFAULT, FINDINGS_LIMIT_MAX, findingCursorOf, findingKind, findingRuleInput, findingStatus, findingStatusInput, listPageQuery, matchesOutboundHost, pageOf, platformRequestFilter, principalId as principalIdSchema, impersonationStamp, promotionAcknowledgement, bindAcknowledgement, rebindAcknowledgement, provisionableJurisdiction, publishVersionInput, queryScopeInput, readScopeTableInput, entityHistoryInput, eventFacetInput, eventCauseInput, eventEffectsInput, invocationEventsInput, deadLettersInput, lifecycleFlowInput, operationSeriesCount, operationSeriesInput, delegatedReadParams, createOrgInput, roleKey as roleKeySchema, peerSwitch, verticalSlug, systemSwitch, DEFAULT_DENIAL_LIMIT, DENIAL_LIMIT_MAX, denialGroupBy, registerVerticalInput, platformScriptCollision, platformScriptRefusal, PLATFORM_SCRIPT_NAMES, serviceDimensions, sweepRunKind, sweepRunOutcome, scopeDump, dataSubjectId as dataSubjectIdSchema, scopeId as scopeIdSchema, scopeStatus, storageShape, surfaceName, tenantId as tenantIdSchema, tenantStatus, versionOrigin, z, PROBLEM_CONTENT_TYPE, toProblem, validationIssuesFrom, redrainEventsInput, importCursorMove, importCursorAcknowledgementMissing, REDRAIN_BATCH, migrationsOnTop, substratError, errorCodeOf, capabilityFilterQuery, capabilityId as capabilityIdSchema, PLATFORM_FEATURES_HEADER, PLATFORM_FEATURE_SCOPE_SWEEPER, } from '@substrat-run/contracts';
4
+ import { permissionKey, parseHostname, withLabel, RESERVED_LABEL_SEPARATOR, adminAction, lakeEventsInput, ownerTransferInput, memberInviteInput, memberRoleInput, ASSET_PART_PREFIX, assetHash, STORE_DRIVERS, STORE_RELEASE_MAX_BYTES, channelName, connectLinkId, connectionActivity, connectionActivitySource, connectionCredential, connectionCertificate, connectionFilter, connectionHealthState, connectionProvider, connectorDispatchKind, PROVISION_SIBLING_KIND, ARCHIVE_SCOPE_KIND, PROVISION_TENANT_KIND, SET_ENTITLEMENTS_KIND, MODEL_USAGE_KIND, SWEEP_RUNS_KIND, toConnectionHealthEntry, CONNECTION_EXPIRY_WARNING_DAYS, CONNECTION_STALE_DAYS, connectionProbe, createTenantInput, entitlementGrantInput, hostname as hostnameSchema, hostnameRegion, hostnameStatus, identityLink, errorCode, issueStatus, issueStatusInput, FINDINGS_LIMIT_DEFAULT, FINDINGS_LIMIT_MAX, findingCursorOf, findingKind, findingRuleInput, findingStatus, findingStatusInput, listPageQuery, matchesOutboundHost, pageOf, platformRequestFilter, principalId as principalIdSchema, impersonationStamp, promotionAcknowledgement, bindAcknowledgement, rebindAcknowledgement, provisionableJurisdiction, publishVersionInput, queryScopeInput, readScopeTableInput, entityHistoryInput, eventFacetInput, eventCauseInput, eventEffectsInput, invocationEventsInput, deadLettersInput, lifecycleFlowInput, operationSeriesCount, operationSeriesInput, delegatedReadParams, createOrgInput, roleKey as roleKeySchema, peerSwitch, verticalSlug, systemSwitch, DEFAULT_DENIAL_LIMIT, DENIAL_LIMIT_MAX, denialGroupBy, registerVerticalInput, platformScriptCollision, platformScriptRefusal, PLATFORM_SCRIPT_NAMES, serviceDimensions, sweepRunKind, sweepRunOutcome, scopeDump, dataSubjectId as dataSubjectIdSchema, scopeId as scopeIdSchema, scopeStatus, storageShape, surfaceName, tenantId as tenantIdSchema, tenantStatus, versionOrigin, z, PROBLEM_CONTENT_TYPE, toProblem, validationIssuesFrom, redrainEventsInput, importCursorMove, importCursorAcknowledgementMissing, REDRAIN_BATCH, migrationsOnTop, substratError, errorCodeOf, capabilityFilterQuery, capabilityId as capabilityIdSchema, PLATFORM_FEATURES_HEADER, PLATFORM_FEATURE_SCOPE_SWEEPER, SOCIAL_RELAY_VERTICALS, } from '@substrat-run/contracts';
5
5
  import { SCOPE_COPY_LEASE_MS, copyRestoreFence, publishedMigrationDigest, replayStoreErasures } from '@substrat-run/kernel';
6
6
  import { attributeFailure } from './failure-attribution.js';
7
7
  import { auditedChange, withAuditedOutcomes } from './audited-change.js';
8
8
  import { BIND_EXPORT_BREAK_REFUSAL, CARRIED_AWAY_KEY, bindExportBreakRefusal, carriedAwayDump, dumpMetaValue, metaValueIn, crossVerticalHealth, exportBreakRefusal, isBindExportBreakRefusal, isExportBreakRefusal, isPrimaryScope, promoteReviewDigest, rebindReviewDigest, assertRebindReviewCurrent, migrationProgress, ulid, auditWarningOf, } from '@substrat-run/kernel';
9
9
  import { TENANT_HEADER, confinedTenant } from './auth.js';
10
10
  import { mintTenantToken } from './tenant-token.js';
11
- import { connectionGrantsForScope } from './vertical-client.js';
11
+ import { connectionGrantsForScope, transferScope } from './vertical-client.js';
12
12
  import { runningVersionOf, runningVersionStoresOf, scopeStoreReachOf, scopeStoresOf, unrouteScope } from './platform-scope-stores.js';
13
13
  import { STORE_REBUILD_REQUEST_SUBREQUESTS, runStoreFleetRebuild, storeRebuildBudget, storeRebuildStatus } from './store-rebuild.js';
14
14
  import { PUSH_HOLD_TTL_MS, runStoreDriverRollout, storeDriverRelease, storedReleaseLoader } from './store-releases.js';
@@ -25,7 +25,7 @@ import { NON_PROBLEM_REFUSAL, coded, mapError, relayed } from './errors.js';
25
25
  import { maskDump, maskRecords } from './mask.js';
26
26
  import { createPseudonymizer } from './pseudonymize.js';
27
27
  import { openDump, sealDump } from './seal.js';
28
- import { assertSandboxContract, verticalUploadBindings, migrationsDigestBindings, deployManifest, storedDeployManifest, pushedPermissionRegistry, deploymentRefFor, stableDeploymentRefFor, nextMigrationTag, upstreamStatusOf, } from './deploy.js';
28
+ import { assertSandboxContract, verticalUploadBindings, migrationsDigestBindings, deployManifest, storedDeployManifest, pushedOwnerGrantProblems, pushedPermissionRegistry, deploymentRefFor, stableDeploymentRefFor, nextMigrationTag, upstreamStatusOf, } from './deploy.js';
29
29
  /**
30
30
  * Answer with a problem document (#113 phase 4).
31
31
  *
@@ -68,6 +68,7 @@ import { STORAGE_PAGE_DEFAULT, STORAGE_PAGE_MAX, readStoragePage } from './stora
68
68
  import { queryLakeEvents } from './lake-gateway.js';
69
69
  import { LakeQueryError } from './r2-sql-engine.js';
70
70
  import { isCustomHostname, validateBindableHostname, } from './custom-hostnames.js';
71
+ import { isSocialRelayVertical, reconcileScopeSocialRelay, relayHostnames, } from './social-relay.js';
71
72
  /**
72
73
  * Response headers carrying the CLI version advisory (`ControlPlaneApiOptions.cliAdvisory`).
73
74
  * The CLI reads these by the same spelling (`packages/cli/src/version.ts`); exported so a
@@ -2276,6 +2277,48 @@ export function createControlPlaneApi(options) {
2276
2277
  open: (items) => c.var.admin.openSubjectPayloads(c.get('actor'), tenantId, scopeId, items),
2277
2278
  });
2278
2279
  const verticalForScope = async (c, scope) => (await deploymentForScope(c, scope))?.client;
2280
+ /**
2281
+ * Reconcile one install's client at the social relay (#1544). Skips — never throws for — an
2282
+ * install the relay is not for: not configured here, not an Auth Server, or no deployment to
2283
+ * deliver to. A relay or delivery failure DOES throw, so a staff route can report it.
2284
+ */
2285
+ const reconcileRelayFor = async (c, tenantId, scopeId) => {
2286
+ if (!options.socialRelay)
2287
+ return { status: 'skipped', reason: 'no social relay is configured on this control plane' };
2288
+ const actor = c.get('actor');
2289
+ return reconcileScopeSocialRelay({
2290
+ relay: options.socialRelay,
2291
+ getScope: (t, s) => c.var.admin.getScopeRecord(actor, tenantIdSchema.parse(t), scopeIdSchema.parse(s)),
2292
+ activeHostnames: async (s) => relayHostnames(await c.var.admin.listHostnames(actor, { scopeId: scopeIdSchema.parse(s), status: 'active' }), {
2293
+ isCustom: custom,
2294
+ provisioner: options.provisionHostname,
2295
+ }),
2296
+ deploymentOf: (scope) => verticalForScope(c, scope),
2297
+ }, tenantId, scopeId);
2298
+ };
2299
+ /**
2300
+ * After a hostname of an Auth Server install became active: register it at the relay. Best
2301
+ * effort, and awaited rather than deferred — the route that activated the hostname has done its
2302
+ * job either way, and a failure here is logged and repaired by the next trigger or a staff run.
2303
+ * Awaited so two activations of one install never reconcile concurrently.
2304
+ */
2305
+ const relayAfterActivation = async (c, before, after) => {
2306
+ if (!options.socialRelay || !after || after.status !== 'active' || before?.status === 'active')
2307
+ return;
2308
+ if (!isSocialRelayVertical(after.verticalSlug))
2309
+ return;
2310
+ try {
2311
+ const outcome = await reconcileRelayFor(c, after.tenantId, after.scopeId);
2312
+ console.log('social-relay.reconciled', { scopeId: after.scopeId, trigger: 'hostname-active', ...outcome });
2313
+ }
2314
+ catch (e) {
2315
+ console.error('social-relay.reconcile.failed', {
2316
+ scopeId: after.scopeId,
2317
+ trigger: 'hostname-active',
2318
+ detail: e instanceof Error ? e.message : String(e),
2319
+ });
2320
+ }
2321
+ };
2279
2322
  /**
2280
2323
  * `verticalForScope`, saying WHICH rung of the ladder chose the client (#1653).
2281
2324
  *
@@ -2664,7 +2707,8 @@ export function createControlPlaneApi(options) {
2664
2707
  await c.var.admin.recordScopeScriptCopy(actor, tenantId, scopeId, servingRef, moveId, { role: 'destination', loadStamp: restoredStamp, leaseMs: copyLeaseMs });
2665
2708
  }
2666
2709
  const erasureEpoch = await c.var.admin.scopeErasureEpoch(actor, tenantId, scopeId);
2667
- const { tables: dump, loadStamp: sourceStamp, revision: sourceRevision } = await retryTransient(() => source.exportScopeStamped(scopeId));
2710
+ // #2450: a page at a time into the destination's stage, so a scope of any size moves.
2711
+ const { dump, loadStamp: sourceStamp, revision: sourceRevision } = await transferScope(source, dest, { from: scopeId }, { retry: retryTransient });
2668
2712
  const restored = await restoreCarryingSwitches(actor, dest, tenantId, scopeId, dump, {
2669
2713
  scopeId, exact: true, loadStamp: restoredStamp,
2670
2714
  ...(moveId ? { fence: copyRestoreFence(moveId, recordedAt, copyLeaseMs, erasureEpoch) } : {}),
@@ -2801,7 +2845,10 @@ export function createControlPlaneApi(options) {
2801
2845
  // cleanup. Name it before any bytes are restored so reap and erasure can find it.
2802
2846
  await c.var.admin.recordScopeScriptCopy(actor, scope.tenantId, scope.id, to, moveId, { role: 'destination', loadStamp: restoredStamp, leaseMs: copyLeaseMs });
2803
2847
  const erasureEpoch = await c.var.admin.scopeErasureEpoch(actor, scope.tenantId, scope.id);
2804
- const { tables: dump, loadStamp: sourceStamp, revision: sourceRevision } = await retryTransient(() => source.exportScopeStamped(scope.id));
2848
+ // #2450: a page at a time into the destination's stage, so a scope of any size moves. The
2849
+ // stage moves neither the destination's load stamp nor its write revision, so the marker read
2850
+ // next still describes the store the restore below commits into.
2851
+ const { dump, loadStamp: sourceStamp, revision: sourceRevision, meta } = await transferScope(source, dest, { from: scope.id }, { retry: retryTransient });
2805
2852
  // What the destination holds now, read before the binding is checked again. The restore
2806
2853
  // sends it back and is refused if the store moved since: another carry into the same script
2807
2854
  // loaded it, or it went live under another carry's bind and took a write. That is a CI retry
@@ -2814,7 +2861,7 @@ export function createControlPlaneApi(options) {
2814
2861
  throw new ControlPlaneError(412, `scope ${scope.id} was re-pointed while its data was being copied out of '${from}', so nothing was ` +
2815
2862
  `moved or bound (#1722). Reload the scope and retry.`);
2816
2863
  }
2817
- if (dumpMetaValue(dump, CARRIED_AWAY_KEY) !== null) {
2864
+ if (dumpMetaValue(meta, CARRIED_AWAY_KEY) !== null) {
2818
2865
  throw new ControlPlaneError(412, `the copy of scope ${scope.id} in '${from}' was already carried to another script and wiped, so nothing ` +
2819
2866
  `was moved or bound (#1722). Reload the scope and retry.`);
2820
2867
  }
@@ -3186,8 +3233,8 @@ export function createControlPlaneApi(options) {
3186
3233
  await releaseIfLive(c, scope, versionId, carried, carried.dest, carried.to);
3187
3234
  let sourceMarker = { loadStamp: carried.sourceStamp, revision: carried.sourceRevision };
3188
3235
  if (await isCarriedAway(carried.dest, scope)) {
3189
- const { tables: dump, loadStamp: stamp, revision } = await retryTransient(() => carried.source.exportScopeStamped(scope.id));
3190
- if (dumpMetaValue(dump, CARRIED_AWAY_KEY) !== null) {
3236
+ const { dump, loadStamp: stamp, revision, meta } = await transferScope(carried.source, carried.dest, { from: scope.id }, { retry: retryTransient });
3237
+ if (dumpMetaValue(meta, CARRIED_AWAY_KEY) !== null) {
3191
3238
  throw new ControlPlaneError(500, `both copies of scope ${scope.id} hold the carried_away tombstone; nothing was wiped`);
3192
3239
  }
3193
3240
  // The re-carry is a copy move of its own (#1722): in the ledger and leased before it
@@ -6364,6 +6411,10 @@ export function createControlPlaneApi(options) {
6364
6411
  if (!registry.success)
6365
6412
  return refuseManifest(registry.error.issues[0], ['registry']);
6366
6413
  }
6414
+ // #2430: an owner grant is a person's, so it holds no key the registry reserves.
6415
+ const ownerGrants = pushedOwnerGrantProblems(checked.data);
6416
+ if (ownerGrants.length > 0)
6417
+ return refuseManifest({ path: ['ownerGrants'], message: ownerGrants.join('; ') });
6367
6418
  }
6368
6419
  await c.var.admin.publishVersion(c.get('actor'), input);
6369
6420
  const version = await c.var.admin.getVersion(c.get('actor'), input.id, slug);
@@ -7066,6 +7117,10 @@ export function createControlPlaneApi(options) {
7066
7117
  if (typeof raw !== 'string')
7067
7118
  return refuse(c, 'validation_failed', 'missing manifest part');
7068
7119
  const manifest = deployManifest.parse(JSON.parse(raw));
7120
+ // #2430: an owner grant is a person's, so it holds no key the registry reserves.
7121
+ const ownerGrants = pushedOwnerGrantProblems(manifest);
7122
+ if (ownerGrants.length > 0)
7123
+ return refuse(c, 'validation_failed', `manifest ownerGrants: ${ownerGrants.join('; ')}`);
7069
7124
  // §4 sandbox contract, before anything reaches the namespace.
7070
7125
  assertSandboxContract(manifest, options.storeDrivers);
7071
7126
  // #2339: a push whose migration digest is not the one its migrations give is refused here,
@@ -8042,8 +8097,52 @@ export function createControlPlaneApi(options) {
8042
8097
  // Re-read so the response carries the post-issuance status + DNS records the caller
8043
8098
  // (dashboard / CLI) renders — a custom bind comes back `verifying` with records.
8044
8099
  const out = (await c.var.admin.listHostnames(c.get('actor'), { scopeId: input.scopeId })).find((h) => h.hostname === input.hostname);
8100
+ // An install's platform hostname binds active here, which is what makes this the
8101
+ // install-time trigger for an Auth Server's relay client (#1544).
8102
+ await relayAfterActivation(c, undefined, out);
8045
8103
  return c.json(out ?? bound, 201);
8046
8104
  });
8105
+ // -- platform-provided social sign-in (#1544) --------------------------------
8106
+ // Staff only: on neither BUILDER_ROUTES nor TENANT_ROUTES, so both default-deny them. The
8107
+ // automatic trigger is a hostname becoming active (`relayAfterActivation`); these are the
8108
+ // levers for everything else — one install, or every Auth Server install after the relay
8109
+ // gained or lost a provider.
8110
+ app.post('/tenants/:tenantId/scopes/:scopeId/social-relay', async (c) => {
8111
+ if (!options.socialRelay)
8112
+ return refuseStatus(c, 501, 'no social relay is configured on this control plane');
8113
+ const tenantId = tenantIdSchema.parse(c.req.param('tenantId'));
8114
+ const scopeId = scopeIdSchema.parse(c.req.param('scopeId'));
8115
+ return c.json(await reconcileRelayFor(c, tenantId, scopeId));
8116
+ });
8117
+ app.post('/social-relay/reconcile', async (c) => {
8118
+ if (!options.socialRelay)
8119
+ return refuseStatus(c, 501, 'no social relay is configured on this control plane');
8120
+ const results = [];
8121
+ for (const vertical of SOCIAL_RELAY_VERTICALS) {
8122
+ const scopes = await c.var.admin.listScopes(c.get('actor'), { vertical, status: ['active'] });
8123
+ // One install at a time: each is a relay call and a delivery, and a fleet in parallel
8124
+ // would be a burst at the relay's single Durable Object for no gain.
8125
+ for (const scope of scopes) {
8126
+ try {
8127
+ results.push({ tenantId: scope.tenantId, scopeId: scope.id, ...(await reconcileRelayFor(c, scope.tenantId, scope.id)) });
8128
+ }
8129
+ catch (e) {
8130
+ results.push({
8131
+ tenantId: scope.tenantId,
8132
+ scopeId: scope.id,
8133
+ status: 'failed',
8134
+ reason: e instanceof Error ? e.message : String(e),
8135
+ });
8136
+ }
8137
+ }
8138
+ }
8139
+ return c.json({
8140
+ delivered: results.filter((r) => r.status === 'delivered').length,
8141
+ skipped: results.filter((r) => r.status === 'skipped').length,
8142
+ failed: results.filter((r) => r.status === 'failed').length,
8143
+ results,
8144
+ });
8145
+ });
8047
8146
  // Re-poll a custom hostname's issuance ("check again" in the dashboard). Tenant-narrowed
8048
8147
  // like the other hostname routes; a platform mint or an already-active row is a no-op
8049
8148
  // re-affirm. Idempotent and safe to hammer — it just reflects Cloudflare's current state.
@@ -8056,7 +8155,9 @@ export function createControlPlaneApi(options) {
8056
8155
  if (!row)
8057
8156
  return refuse(c, 'not_found', `unknown hostname: ${name.toLowerCase()}`);
8058
8157
  await runIssuance(c.var.admin, c.get('actor'), row);
8059
- return c.json(await hostnameRow(c, name));
8158
+ const after = await hostnameRow(c, name);
8159
+ await relayAfterActivation(c, row, after);
8160
+ return c.json(after);
8060
8161
  });
8061
8162
  app.patch('/hostnames/:hostname/status', async (c) => {
8062
8163
  const { status, note } = setHostnameStatusBody.parse(await c.req.json());
@@ -8066,8 +8167,10 @@ export function createControlPlaneApi(options) {
8066
8167
  if (confinedTenant(c.get('principal')) !== null && !(await tenantHostname(c, name))) {
8067
8168
  return refuse(c, 'not_found', `unknown hostname: ${name.toLowerCase()}`);
8068
8169
  }
8170
+ const before = await hostnameRow(c, name);
8069
8171
  await c.var.admin.setHostnameStatus(c.get('actor'), name, status, note);
8070
8172
  const row = (await c.var.admin.listHostnames(c.get('actor'), {})).find((h) => h.hostname === name.toLowerCase());
8173
+ await relayAfterActivation(c, before, row);
8071
8174
  return c.json(row);
8072
8175
  });
8073
8176
  // Unbind (hard-delete) a hostname row — what the orphan cleanup uses on rows
@@ -8458,6 +8561,8 @@ export function createControlPlaneApi(options) {
8458
8561
  let row;
8459
8562
  /** `fenced`: the ledger stamp and lease of this fork's restore (#1722), when it has one. */
8460
8563
  let restore;
8564
+ /** #2450: the fork's data, moved into the preview's copy once the ledger names it. */
8565
+ let forkData = null;
8461
8566
  /** #2009: the directory's classification of the row below, which every restore of it carries. */
8462
8567
  const markCopyOfRow = () => {
8463
8568
  const lineage = copyLineageOf({ kind: row.kind ?? '', forkedFrom: row.forkedFrom ?? null });
@@ -8472,7 +8577,14 @@ export function createControlPlaneApi(options) {
8472
8577
  throw new ControlPlaneError(501, 'preview needs dispatch resolution for the PR version');
8473
8578
  }
8474
8579
  const canonical = await c.var.admin.exportScope(actor, tenantId, source.id);
8475
- const tables = sourceClient ? await sourceClient.exportScope(source.id) : canonical.tables;
8580
+ // #2450: from a vertical, the fork's data moves a page at a time into the preview's own stage
8581
+ // there, so a scope of any size forks. Unstamped, as the whole export was: a fork writes
8582
+ // nothing into its source. Moved once, after the row and the ledger name the preview's copy
8583
+ // (K-31: no copied data without a record) and ahead of the restore's own retries, so a
8584
+ // restore blip reloads the same stage and an export fault is not recorded as a restore's.
8585
+ forkData = sourceClient
8586
+ ? async () => (await transferScope(sourceClient, target, { from: source.id, to: previewId }, { retry: retryTransient, stamp: false })).dump
8587
+ : async () => canonical.tables;
8476
8588
  // Directory row FIRST as `provisioning` (K-31 two-phase): a crash before the data
8477
8589
  // copy leaves an inert row that — carrying `forkedFrom` + `expiresAt` — the GC sweep
8478
8590
  // reaps, never copied data with no record.
@@ -8495,7 +8607,7 @@ export function createControlPlaneApi(options) {
8495
8607
  // pushes a fresh version per try) — #559 (2).
8496
8608
  // #2009: a load classifies nothing by itself, so the restore carries the directory's
8497
8609
  // classification of the row below, as every restore onto a non-primary scope does.
8498
- restore = (fenced) => target.restoreScope(tenantId, previewId, tables, { sourceScopeId: source.id, exact: true, ...markCopyOfRow(), ...fenced });
8610
+ restore = (fenced, dump) => target.restoreScope(tenantId, previewId, dump ?? [], { sourceScopeId: source.id, exact: true, ...markCopyOfRow(), ...fenced });
8499
8611
  }
8500
8612
  else {
8501
8613
  // A clean-room preview (#509 (b)): an EMPTY scope, no source to export. No `forkedFrom`
@@ -8541,7 +8653,8 @@ export function createControlPlaneApi(options) {
8541
8653
  fenced = { loadStamp: restoredStamp, fence: copyRestoreFence(moveId, recordedAt, copyLeaseMs, erasureEpoch) };
8542
8654
  }
8543
8655
  const load = restore;
8544
- await restoreOrRecord(() => load(fenced));
8656
+ const dump = forkData ? await forkData() : undefined;
8657
+ await restoreOrRecord(() => load(fenced, dump));
8545
8658
  }
8546
8659
  await c.var.admin.activateScope(actor, tenantId, previewId);
8547
8660
  // Bind the PR version. A private vertical's push self-admitted, so this is accepted; a