@codemem/server 0.47.2 → 0.47.3

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/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { closeSync, existsSync, fstatSync, fsyncSync, linkSync, lstatSync, mkdirSync, openSync, readFileSync, statSync, unlinkSync, writeFileSync } from "node:fs";
2
2
  import { basename, dirname, isAbsolute, join, posix, resolve, win32 } from "node:path";
3
- import { ACCESS_CLEANUP_OP_TYPE, CodememConfigMutationError, CoordinatorAccountLinkError, CoordinatorReciprocalApprovalRequestChangedError, DEFAULT_TIME_WINDOW_S, FILE_CONTEXT_TRANSPORT_MAX_BYTES, LEGACY_SHARED_REVIEW_SCOPE_ID, LOCAL_DEFAULT_SCOPE_ID, LOCAL_SYNC_CAPABILITY, LOCAL_SYNC_FEATURES, LegacyTeamSetupAdditiveConvergenceError, LegacyTeamSetupRosterCapacityError, MEMORY_FILTER_FIELD_TYPES, MEMORY_FILTER_NAMES, MEMORY_KIND_DESCRIPTIONS, MemoryStore, ObserverClient, PROMPT_TRANSPORT_PROTOCOL_RANGE, REMEMBER_MEMORY_KINDS, RICH_TIER_ANTHROPIC_DEFAULTS, RICH_TIER_DEFAULTS, RawEventIngestValidationError, RecipientPolicyEdgeRequestError, RecipientPolicyTeamRenameError, RemoteCoordinatorRequestError, SCOPE_MEMBERSHIP_REVOCATION_LIMITATION, SIMPLE_TIER_ANTHROPIC_DEFAULTS, SIMPLE_TIER_DEFAULTS, SYNC_AUTHORIZATION_REFRESH_HEADER, SYNC_CAPABILITY_HEADER, SYNC_FEATURES_HEADER, SYNC_SCOPE_QUERY_PARAM, VERSION, VERSION as VERSION$1, VIEWER_IDENTITY_TARGET_KEYS, VIEWER_SERVICE_DISCRIMINATOR, addSyncScopeToBoundary, analyzeProjectScopeMappingChangeGuardrails, analyzeProjectScopeMappingChangesGuardrails, analyzeProjectScopeMappingDeletionGuardrails, applyLegacyTeamSetupCompletionManifest, applyLegacyTeamSetupCompletionManifestAndReturnActivation, applyLocalIdentitySwitch, applyReplicationOps, areLegacyTeamSetupCompletionPolicyFactsAdditivelyCompatible, assertNoLocalIdentityOverride, automaticRecallHealth, buildAuthHeaders, buildBaseUrl, buildDirectPeerAuthHeaders, buildDistillReport, buildFilterBranchesWithContext, buildFilterClausesWithContext, buildPiFlushSignalFromEvent, buildRawEventEnvelopeFromCodexHook, buildRawEventEnvelopeFromHook, buildRawEventEnvelopeFromPiEvent, buildViewerIdentityTarget, canonicalCoordinatorLegacyTeamCompletionManifestJson, canonicalMemoryKind, canonicalRepositoryProjectIdentity, canonicalWorkspaceIdentity, captureAccountOwnerProfilePins, changeCoordinatorAccount, claimRecipientPolicyActorMutations, claimRecipientPolicyPublicationMutation, classifyRecordedSyncFailure, cleanupNonces, clearLegacyTeamSetupDeviceDecision, clonePromptPackAttempt, coerceObserverCommand, commitDeviceIdentityBindings, commitRecipientPolicyEdges, completeLocalIdentitySwitch, containLegacyTeamSetupCompletionConflict, coordinatorArchiveGroupAction, coordinatorAuthControllerReviewAction, coordinatorCreateAddDeviceInviteAction, coordinatorCreateGroupAction, coordinatorCreateInviteAction, coordinatorCreateLegacyTeamCompletionAction, coordinatorCreateScopeAction, coordinatorDisableDeviceAction, coordinatorEnableDeviceAction, coordinatorGetLegacyTeamCompletionAction, coordinatorGrantScopeMembershipAction, coordinatorImportInviteAction, coordinatorListBootstrapGrantsAction, coordinatorListConsumedTeamInvitesAction, coordinatorListDevicesAction, coordinatorListGroupsAction, coordinatorListJoinRequestsAction, coordinatorListLegacyTeamCompletionsAction, coordinatorListReviewedRecipientInviteEvidenceAction, coordinatorListScopeMembershipsAction, coordinatorListScopesAction, coordinatorRemoveDeviceAction, coordinatorRenameDeviceAction, coordinatorRenameGroupAction, coordinatorReviewJoinRequestAction, coordinatorRevokeBootstrapGrantAction, coordinatorRevokeScopeMembershipAction, coordinatorStatusSnapshot, coordinatorUnarchiveGroupAction, coordinatorUpdateScopeAction, countShareableProjectMemories, createCoordinatorReciprocalApproval, decodeInvitePayload, dedupeOrderedIds, defaultSpaceScopeIdForGroup, deleteProjectScopeSettingsMapping, deriveLegacyTeamSetupCompletionManifest, detectInstallKind, deterministicPolicyTeamId, diagnoseStalePeerReceivedRows, discoverLegacyTeamCandidates, dispatchFileContextTransport, ensureDeviceIdentity, executeShareProvisioning, extractInvitePayload, extractReplicationOps, filterReplicationOpsForSyncWithStatus, fingerprintPublicKey, formatHostPort, friendlyDeviceName, fromJson, generateWithOpenCodeV2, getCodememConfigPath, getCodememEnvOverrideValues, getCodememEnvOverrides, getCoordinatorEnrollmentReconciliationIssueSummary, getCoordinatorGroupPreference, getEffectiveCachedScopeAuthorization, getLegacyTeamSetupDraft, getRecipientPolicyAuthorityState, getSemanticIndexDiagnostics, getSyncResetState, getUpdateStatus, ingestRawEvents, inspectFreshLegacyTeamSetupActivation, inspectLegacyTeamSetupActivation, inviteTokenDigest, isAutomaticRecallMeasurement, isLegacyTeamCandidateSelectable, isLegacyTeamSetupProjectMappingIdentity, isPeerTrustBindingCompatible, isProjectSyncEnablementError, isScopedSyncCapability, judgeDistillReport, legacyDecisionCountsAsOwner, legacyTeamCandidateId, legacyTeamCandidateProjectInventory, legacyTeamCanonicalProjectRef, legacyTeamDeviceRef, legacyTeamResolvedProjectRef, legacyTeamSetupApiErrorCode, linkCoordinatorAccount, listAuthorizedScopesForPeer, listCoordinatorJoinRequests, listDeviceIdentityInventory, listInboundScopeRejections, listLegacyRecipientPolicyProjections, listMaintenanceJobs, listObserverProviderOptions, listOpenCodeV2Models, listPerPeerScopeSyncState, listProjectScopeCandidates, listProjectScopeInventory, listProjectScopeSettingsMappings, listRecipientPolicyIntent, listRecipientPolicyReview, listSharingDomainSettingsScopes, loadMemorySnapshotPageForPeer, loadPublicKey, loadReplicationOpsForPeer, loadRuntimeSigningPublicKey, lookupCoordinatorPeers, markLocalIdentitySwitchBound, markLocalIdentitySwitchNotCommitted, memoryFilterValueMatchesType, mergeAddresses, migrateRecipientPolicyIntent, mutateCodememConfigFile, negotiateSyncCapability, normalizeAddress, normalizeCoordinatorAccountLinkOrigin, normalizeCoordinatorLegacyTeamCompletionManifest, normalizeHumanPresentationName, normalizeSyncCapability, normalizeSyncFeatures, normalizeTeammateName, parseAcceptedProjectIntent, parseBootstrapExpiry, parseFileContextTransportRequest, parsePositiveMemoryId, parseReassignScopePayload, parseRecipientPolicyEdgeCommitRequest, parseStrictInteger, parseSyncScopeRequest, persistShareOperation, personalScopeGrantStatusForPeer, planShareOperation, previewDeviceIdentityBindings, previewLegacyTeamSetupActivation, previewRecipientPolicyEdges, previewRecipientPolicyOnboarding, previewRecipientPolicyOnboardingFromReviewedIntent, probeAvailableCredentials, projectMatchesFilter, projectShareLifecycle, promptPackArtifactFingerprint, readAccountLinkDevice, readAccountOwnerAssociation, readAccountOwnerAssociationRetainedAtMs, readCodememConfigFile, readCompletedLocalIdentitySwitches, readCoordinatorAccountChangeCapabilities, readCoordinatorAccountLinkStatus, readCoordinatorResolvedAccountOwnerReceiptStatus, readCoordinatorResolvedAccountOwnerStatus, readCoordinatorSyncConfig, readOpenLocalIdentitySwitch, reassignProjectScopeInventoryProject, recipientInviteAuthoritativeIdentityId, recipientPolicyDigest, recipientReviewedIntentDigest, reconcileCoordinatorEnrollmentSnapshot, reconcileRecipientPolicyProject, reconcileShareOperationAcceptance, reconstructLegacyTeamSetupCompletionManifest, recordAutomaticRecall, recordHighestObservedDirectSignatureVersion, recordLocalIdentitySwitch, recordNonce, recordPromptPackArtifacts, recordPromptPackTerminal, refreshAuthorizedCoordinatorPeerTrust, refreshConfiguredScopeMembershipCache, refreshLegacyTeamCandidate, rejectInboundScopeFailures, renameRecipientPolicyTeam, replayLegacyTeamSetupActivation, repositoryIdentitiesByWorkspace, repositoryIdentityForWorkspace, requestJson, requireLegacyTeamSetupAccessDeltaWithinLimit, resolveCodememConfigPath, resolveDbPath, resolveObserverDefaultModel, resolveObserverRuntime, resolveProject, resolveProjectRoot, resolveRecipientPolicyReview, resolveRecipientPolicyReviewBulk, resolveVisibleScopeIds, resumeDeviceRebind, runDeviceRebind, runSyncPass, schema, scopeAuthorizationFailureReason, searchPiSessions, serializeRecipientPolicyCoordinatorGroupMutation, serializeRecipientPolicyPublicationMutation, serializeRecipientPolicyTeamMutation, setLegacyTeamSetupDeviceAssignment, setLegacyTeamSetupDeviceDecision, setLegacyTeamSetupProjectMapping, summarizeInboundScopeRejections, summaryLikeSqlPredicate, supportsSyncFeature, syncScopeResetRequiredPayload, toJson, tryUpdateRetrievalDelivery, updatePeerAddresses, upsertCoordinatorGroupPreference, upsertProjectScopeSettingsMappings, validateLegacyTeamSetupCompletionManifest, validateLegacyTeamSetupCompletionManifestBinding, validateRawEvents, verifyDirectPeerSignature, verifyRecipientReviewedIntent, verifySignature, wakeRecipientPoliciesForIdentities, wakeRecipientPoliciesForProjectIdentities } from "@codemem/core";
3
+ import { ACCESS_CLEANUP_OP_TYPE, CodememConfigMutationError, CoordinatorAccountLinkError, CoordinatorReciprocalApprovalRequestChangedError, DEFAULT_TIME_WINDOW_S, FILE_CONTEXT_TRANSPORT_MAX_BYTES, LEGACY_SHARED_REVIEW_SCOPE_ID, LOCAL_DEFAULT_SCOPE_ID, LOCAL_SYNC_CAPABILITY, LOCAL_SYNC_FEATURES, LegacyTeamSetupAdditiveConvergenceError, LegacyTeamSetupRosterCapacityError, MEMORY_FILTER_FIELD_TYPES, MEMORY_FILTER_NAMES, MEMORY_KIND_DESCRIPTIONS, MemoryStore, ObserverClient, PROMPT_TRANSPORT_PROTOCOL_RANGE, REMEMBER_MEMORY_KINDS, RICH_TIER_ANTHROPIC_DEFAULTS, RICH_TIER_DEFAULTS, RawEventIngestValidationError, RecipientPolicyEdgeRequestError, RecipientPolicyTeamRenameError, RemoteCoordinatorRequestError, SCOPE_MEMBERSHIP_REVOCATION_LIMITATION, SIMPLE_TIER_ANTHROPIC_DEFAULTS, SIMPLE_TIER_DEFAULTS, SYNC_AUTHORIZATION_REFRESH_HEADER, SYNC_CAPABILITY_HEADER, SYNC_FEATURES_HEADER, SYNC_SCOPE_QUERY_PARAM, VERSION, VERSION as VERSION$1, VIEWER_IDENTITY_TARGET_KEYS, VIEWER_SERVICE_DISCRIMINATOR, addSyncScopeToBoundary, analyzeProjectScopeMappingChangeGuardrails, analyzeProjectScopeMappingChangesGuardrails, analyzeProjectScopeMappingDeletionGuardrails, applyLegacyTeamSetupCompletionManifest, applyLegacyTeamSetupCompletionManifestAndReturnActivation, applyLocalIdentitySwitch, applyReplicationOps, areLegacyTeamSetupCompletionPolicyFactsAdditivelyCompatible, assertNoLocalIdentityOverride, automaticRecallHealth, buildAuthHeaders, buildBaseUrl, buildDirectPeerAuthHeaders, buildDistillReport, buildFilterBranchesWithContext, buildFilterClausesWithContext, buildPiFlushSignalFromEvent, buildRawEventEnvelopeFromCodexHook, buildRawEventEnvelopeFromHook, buildRawEventEnvelopeFromPiEvent, buildViewerIdentityTarget, canonicalCoordinatorLegacyTeamCompletionManifestJson, canonicalMemoryKind, canonicalRepositoryProjectIdentity, canonicalWorkspaceIdentity, captureAccountOwnerProfilePins, changeCoordinatorAccount, claimRecipientPolicyActorMutations, claimRecipientPolicyPublicationMutation, classifyRecordedSyncFailure, cleanupNonces, clearLegacyTeamSetupDeviceDecision, clonePromptPackAttempt, coerceObserverCommand, commitDeviceIdentityBindings, commitRecipientPolicyEdges, completeLocalIdentitySwitch, containLegacyTeamSetupCompletionConflict, coordinatorArchiveGroupAction, coordinatorAuthControllerReviewAction, coordinatorCreateAddDeviceInviteAction, coordinatorCreateGroupAction, coordinatorCreateInviteAction, coordinatorCreateLegacyTeamCompletionAction, coordinatorCreateScopeAction, coordinatorDisableDeviceAction, coordinatorEnableDeviceAction, coordinatorGetLegacyTeamCompletionAction, coordinatorGrantScopeMembershipAction, coordinatorImportInviteAction, coordinatorListBootstrapGrantsAction, coordinatorListConsumedTeamInvitesAction, coordinatorListDevicesAction, coordinatorListGroupsAction, coordinatorListJoinRequestsAction, coordinatorListLegacyTeamCompletionsAction, coordinatorListReviewedRecipientInviteEvidenceAction, coordinatorListScopeMembershipsAction, coordinatorListScopesAction, coordinatorRemoveDeviceAction, coordinatorRenameDeviceAction, coordinatorRenameGroupAction, coordinatorReviewJoinRequestAction, coordinatorRevokeBootstrapGrantAction, coordinatorRevokeScopeMembershipAction, coordinatorStatusSnapshot, coordinatorUnarchiveGroupAction, coordinatorUpdateScopeAction, countShareableProjectMemories, createCoordinatorReciprocalApproval, decodeInvitePayload, dedupeOrderedIds, defaultSpaceScopeIdForGroup, deleteProjectScopeSettingsMapping, deriveLegacyTeamSetupCompletionManifest, detectInstallKind, deterministicPolicyTeamId, diagnoseStalePeerReceivedRows, discoverLegacyTeamCandidates, dispatchFileContextTransport, ensureDeviceIdentity, executeShareProvisioning, extractInvitePayload, extractReplicationOps, filterReplicationOpsForSyncWithStatus, fingerprintPublicKey, formatHostPort, friendlyDeviceName, fromJson, generateWithOpenCodeV2, getCodememConfigPath, getCodememEnvOverrideValues, getCodememEnvOverrides, getCoordinatorEnrollmentReconciliationIssueSummary, getCoordinatorGroupPreference, getEffectiveCachedScopeAuthorization, getLegacyTeamSetupDraft, getRecipientPolicyAuthorityState, getSemanticIndexDiagnostics, getSyncResetState, getUpdateStatus, ingestRawEvents, inspectFreshLegacyTeamSetupActivation, inspectLegacyTeamSetupActivation, inviteTokenDigest, isAutomaticRecallMeasurement, isLegacyTeamCandidateSelectable, isLegacyTeamSetupProjectMappingIdentity, isPeerTrustBindingCompatible, isProjectSyncEnablementError, isScopedSyncCapability, judgeDistillReport, legacyDecisionCountsAsOwner, legacyTeamCandidateId, legacyTeamCandidateProjectInventory, legacyTeamCanonicalProjectRef, legacyTeamDeviceRef, legacyTeamResolvedProjectRef, legacyTeamSetupApiErrorCode, legacyTeamSetupCompletionActorIds, legacyTeamSetupFailureCheck, linkCoordinatorAccount, listAuthorizedScopesForPeer, listCoordinatorJoinRequests, listDeviceIdentityInventory, listInboundScopeRejections, listLegacyRecipientPolicyProjections, listMaintenanceJobs, listObserverProviderOptions, listOpenCodeV2Models, listPerPeerScopeSyncState, listProjectScopeCandidates, listProjectScopeInventory, listProjectScopeSettingsMappings, listRecipientPolicyIntent, listRecipientPolicyReview, listSharingDomainSettingsScopes, loadMemorySnapshotPageForPeer, loadPublicKey, loadReplicationOpsForPeer, loadRuntimeSigningPublicKey, lookupCoordinatorPeers, markLocalIdentitySwitchBound, markLocalIdentitySwitchNotCommitted, memoryFilterValueMatchesType, mergeAddresses, migrateRecipientPolicyIntent, mutateCodememConfigFile, negotiateSyncCapability, normalizeAddress, normalizeCoordinatorAccountLinkOrigin, normalizeCoordinatorLegacyTeamCompletionManifest, normalizeHumanPresentationName, normalizeSyncCapability, normalizeSyncFeatures, normalizeTeammateName, parseAcceptedProjectIntent, parseBootstrapExpiry, parseFileContextTransportRequest, parsePositiveMemoryId, parseReassignScopePayload, parseRecipientPolicyEdgeCommitRequest, parseStrictInteger, parseSyncScopeRequest, persistShareOperation, personalScopeGrantStatusForPeer, planShareOperation, previewDeviceIdentityBindings, previewLegacyTeamSetupActivation, previewRecipientPolicyEdges, previewRecipientPolicyOnboarding, previewRecipientPolicyOnboardingFromReviewedIntent, probeAvailableCredentials, projectMatchesFilter, projectShareLifecycle, promptPackArtifactFingerprint, readAccountLinkDevice, readAccountOwnerAssociation, readAccountOwnerAssociationRetainedAtMs, readCodememConfigFile, readCompletedLocalIdentitySwitches, readCoordinatorAccountChangeCapabilities, readCoordinatorAccountLinkStatus, readCoordinatorResolvedAccountOwnerReceiptStatus, readCoordinatorResolvedAccountOwnerStatus, readCoordinatorSyncConfig, readOpenLocalIdentitySwitch, reassignProjectScopeInventoryProject, recipientInviteAuthoritativeIdentityId, recipientPolicyDigest, recipientReviewedIntentDigest, reconcileCoordinatorEnrollmentSnapshot, reconcileRecipientPolicyProject, reconcileShareOperationAcceptance, reconstructLegacyTeamSetupCompletionManifest, recordAutomaticRecall, recordHighestObservedDirectSignatureVersion, recordLocalIdentitySwitch, recordNonce, recordPromptPackArtifacts, recordPromptPackTerminal, refreshAuthorizedCoordinatorPeerTrust, refreshConfiguredScopeMembershipCache, refreshLegacyTeamCandidate, rejectInboundScopeFailures, renameRecipientPolicyTeam, replayLegacyTeamSetupActivation, repositoryIdentitiesByWorkspace, repositoryIdentityForWorkspace, requestJson, requireLegacyTeamSetupAccessDeltaWithinLimit, resolveCodememConfigPath, resolveDbPath, resolveObserverDefaultModel, resolveObserverRuntime, resolveProject, resolveProjectRoot, resolveRecipientPolicyReview, resolveRecipientPolicyReviewBulk, resolveVisibleScopeIds, resumeDeviceRebind, runDeviceRebind, runSyncPass, schema, scopeAuthorizationFailureReason, searchPiSessions, serializeRecipientPolicyActorMutations, serializeRecipientPolicyCoordinatorGroupMutation, serializeRecipientPolicyPublicationMutation, serializeRecipientPolicyTeamMutation, setLegacyTeamSetupDeviceAssignment, setLegacyTeamSetupDeviceDecision, setLegacyTeamSetupProjectMapping, summarizeInboundScopeRejections, summaryLikeSqlPredicate, supportsSyncFeature, syncScopeResetRequiredPayload, toJson, tryUpdateRetrievalDelivery, updatePeerAddresses, upsertCoordinatorGroupPreference, upsertProjectScopeSettingsMappings, validateLegacyTeamSetupCompletionManifest, validateLegacyTeamSetupCompletionManifestBinding, validateRawEvents, verifyDirectPeerSignature, verifyRecipientReviewedIntent, verifySignature, wakeRecipientPoliciesForIdentities, wakeRecipientPoliciesForProjectIdentities } from "@codemem/core";
4
4
  import { serveStatic } from "@hono/node-server/serve-static";
5
5
  import { Hono } from "hono";
6
6
  import { createCipheriv, createDecipheriv, createHash, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
@@ -6360,6 +6360,23 @@ var MAX_PROJECT_MAPPING_METADATA_ROWS = 1e4;
6360
6360
  var MAX_MUTATION_BODY_BYTES = 8192;
6361
6361
  var SUMMARY_SNAPSHOT_CACHE_TTL_MS = 3e4;
6362
6362
  var COORDINATOR_ROSTER_READ_BUDGET_MS = 6e4;
6363
+ function serializeCanonicalManifestMutation(store, groupId, manifest, operation) {
6364
+ return serializeRecipientPolicyPublicationMutation(store.db, () => {
6365
+ const actorIds = legacyTeamSetupCompletionActorIds(store.db, manifest);
6366
+ return serializeRecipientPolicyActorMutations(store.db, actorIds, () => serializeRecipientPolicyTeamMutation(store.db, manifest.team_id, () => serializeRecipientPolicyCoordinatorGroupMutation(store.db, groupId, () => operation(actorIds))));
6367
+ });
6368
+ }
6369
+ function finishDraftActorIds(draft) {
6370
+ return draft.devices.flatMap((device) => [...device.decision === "included" && device.targetIdentityId ? [device.targetIdentityId] : [], ...device.existingIdentityId ? [device.existingIdentityId] : []]);
6371
+ }
6372
+ function completionRecipientPolicyLocksHeld(actorIds) {
6373
+ return {
6374
+ publication: true,
6375
+ actors: actorIds,
6376
+ team: true,
6377
+ coordinatorGroup: true
6378
+ };
6379
+ }
6363
6380
  var TEAM_SETUP_ROUTE_PREFIX = "/api/sync/team-setup/v1";
6364
6381
  var CANDIDATE_REF_PATTERN = /^legacy-team-candidate:[0-9a-f]{32}$/u;
6365
6382
  var DEVICE_REF_PATTERN = /^legacy-team-device-ref-v1:[0-9a-f]{64}$/u;
@@ -6405,6 +6422,47 @@ async function runCandidateMutation(db, candidateRef, operation) {
6405
6422
  release();
6406
6423
  }
6407
6424
  }
6425
+ function completionFailureHandlers(options) {
6426
+ const handledGroupIds = /* @__PURE__ */ new Set();
6427
+ const reportFailure = (group, error) => {
6428
+ handledGroupIds.add(group.groupId);
6429
+ options.onFailure?.(group, error);
6430
+ };
6431
+ const handleFailure = (group, error) => {
6432
+ if (!options.isolateApplyFailures) throw error;
6433
+ reportFailure(group, error);
6434
+ };
6435
+ return {
6436
+ handledGroupIds,
6437
+ handleFailure,
6438
+ reportFailure
6439
+ };
6440
+ }
6441
+ function completionConflictError(cause) {
6442
+ return new Error("team_setup_completion_conflict", { cause });
6443
+ }
6444
+ function addFreshCompletionGroups(index, groups, keyOf) {
6445
+ for (const group of groups) {
6446
+ if (!group) continue;
6447
+ const key = keyOf(group);
6448
+ if (index.has(key)) throw new Error("team_setup_completion_invalid");
6449
+ index.set(key, group);
6450
+ }
6451
+ }
6452
+ function groupCompletionFailureHandler(groups, handleFailure) {
6453
+ return (groupId, error) => {
6454
+ const group = groups.get(groupId);
6455
+ if (group) handleFailure(group, error);
6456
+ };
6457
+ }
6458
+ function summaryReconciliationOptions(blockingErrors) {
6459
+ return {
6460
+ isolateApplyFailures: true,
6461
+ onFailure: (group, error) => {
6462
+ blockingErrors.set(legacyTeamCandidateId(group.coordinatorId, group.groupId), apiErrorCode(new Error(completionApiError(error))));
6463
+ }
6464
+ };
6465
+ }
6408
6466
  var defaultCompletionDependencies = {
6409
6467
  create: coordinatorCreateLegacyTeamCompletionAction,
6410
6468
  get: coordinatorGetLegacyTeamCompletionAction,
@@ -6496,13 +6554,17 @@ function isUnsupportedCompletionQuery(error) {
6496
6554
  function isUnattributableCompletionBatchError(error) {
6497
6555
  return error instanceof Error && (error.message === "coordinator_completion_response_malformed" || error.message === "coordinator_completion_group_mismatch");
6498
6556
  }
6499
- async function listCompletionRecordsPerGroup(groupIds, list) {
6500
- if (groupIds.length < 2) return [];
6557
+ async function listCompletionRecordsPerGroup(groupIds, list, onFailure, batchError) {
6558
+ if (groupIds.length === 1) {
6559
+ onFailure(groupIds[0], batchError);
6560
+ return [];
6561
+ }
6501
6562
  const records = [];
6502
6563
  for (const groupId of groupIds) try {
6503
6564
  records.push(...await list([groupId]));
6504
6565
  } catch (error) {
6505
6566
  if (!isUnattributableCompletionBatchError(error)) throw error;
6567
+ onFailure(groupId, error);
6506
6568
  }
6507
6569
  return records;
6508
6570
  }
@@ -6736,6 +6798,55 @@ function candidateFromDraft(draft) {
6736
6798
  unresolvedProjectCount: draft.unresolvedProjectCount
6737
6799
  };
6738
6800
  }
6801
+ function blockedCandidateSummary(store, group, blockingError) {
6802
+ const candidateRef = legacyTeamCandidateId(group.coordinatorId, group.groupId);
6803
+ const draft = getLegacyTeamSetupDraft(store.db, candidateRef);
6804
+ if (draft) return {
6805
+ ...candidateSummary(candidateFromDraft(draft)),
6806
+ status: "stale",
6807
+ blockingError
6808
+ };
6809
+ const forbiddenIds = [
6810
+ group.coordinatorId,
6811
+ group.groupId,
6812
+ candidateRef,
6813
+ ...group.devices.flatMap((device) => [
6814
+ device.deviceId,
6815
+ device.fingerprint,
6816
+ ...device.labelRedactionIds ?? []
6817
+ ])
6818
+ ];
6819
+ return {
6820
+ candidateRef,
6821
+ displayName: safeChoiceLabel(group.displayName, "Legacy Team", forbiddenIds),
6822
+ status: "stale",
6823
+ blockingError,
6824
+ deviceCount: group.devices.length,
6825
+ projectCount: 0,
6826
+ unresolvedDeviceCount: 0,
6827
+ unresolvedProjectCount: 0
6828
+ };
6829
+ }
6830
+ function pendingCandidateSummaries(store, groups, blockingErrors) {
6831
+ const pending = readPureCandidateViews(store, groups.filter((group) => !blockingErrors.has(legacyTeamCandidateId(group.coordinatorId, group.groupId)))).map(candidateSummary).filter((candidate) => candidate.status !== "ready");
6832
+ const blocked = groups.flatMap((group) => {
6833
+ const error = blockingErrors.get(legacyTeamCandidateId(group.coordinatorId, group.groupId));
6834
+ return error ? [blockedCandidateSummary(store, group, error)] : [];
6835
+ });
6836
+ return [...pending, ...blocked].toSorted((left, right) => {
6837
+ if (left.candidateRef < right.candidateRef) return -1;
6838
+ return left.candidateRef > right.candidateRef ? 1 : 0;
6839
+ });
6840
+ }
6841
+ async function reconcileSummaryCandidates(store, groups, reconcile) {
6842
+ readPureCandidateViews(store, groups);
6843
+ const blockingErrors = /* @__PURE__ */ new Map();
6844
+ await reconcile(store, groups, summaryReconciliationOptions(blockingErrors));
6845
+ return {
6846
+ version: TEAM_SETUP_VERSION,
6847
+ candidates: pendingCandidateSummaries(store, groups, blockingErrors)
6848
+ };
6849
+ }
6739
6850
  function readPureCandidateViews(store, groups) {
6740
6851
  const existing = [];
6741
6852
  const discoverable = [];
@@ -7100,6 +7211,20 @@ function apiErrorCode(error) {
7100
7211
  const code = legacyTeamSetupApiErrorCode(error);
7101
7212
  return code === "team_setup_projection_changed" ? "team_setup_conflict" : code;
7102
7213
  }
7214
+ /**
7215
+ * Maps a setup failure to its API code and logs the internal check that raised
7216
+ * it. Dozens of checks share each public code, so the log is the only place an
7217
+ * operator can see which one failed.
7218
+ */
7219
+ function teamSetupFailure(error, route) {
7220
+ const code = apiErrorCode(error);
7221
+ const check = legacyTeamSetupFailureCheck(error);
7222
+ console.warn(`[team-setup] route=${route} apiCode=${code}${check ? ` check=${check}` : ""}`);
7223
+ return {
7224
+ code,
7225
+ status: errorStatus$1(code)
7226
+ };
7227
+ }
7103
7228
  function completionApiError(error) {
7104
7229
  const code = legacyTeamSetupApiErrorCode(error);
7105
7230
  return code === "team_setup_failed" ? "team_setup_completion_unavailable" : code;
@@ -7438,29 +7563,26 @@ function teamSetupRoutes(options) {
7438
7563
  */
7439
7564
  async function applyCanonicalManifestIfStillAuthorized(store, authorization, group, manifest, freshRoster) {
7440
7565
  let outcome = "unauthorized";
7441
- return await runCandidateMutation(store.db, legacyTeamCandidateId(group.coordinatorId, group.groupId), () => serializeRecipientPolicyPublicationMutation(store.db, () => serializeRecipientPolicyTeamMutation(store.db, manifest.team_id, () => serializeRecipientPolicyCoordinatorGroupMutation(store.db, group.groupId, async () => {
7566
+ return await runCandidateMutation(store.db, legacyTeamCandidateId(group.coordinatorId, group.groupId), () => serializeCanonicalManifestMutation(store, group.groupId, manifest, async (actorIds) => {
7442
7567
  if (!stillAuthorizesGroup(authorization, group)) return;
7443
7568
  await applyLegacyTeamSetupCompletionManifest(store.db, {
7444
7569
  coordinatorId: group.coordinatorId,
7445
7570
  groupId: group.groupId,
7446
7571
  manifest,
7447
7572
  freshRoster,
7448
- recipientPolicyLocksHeld: {
7449
- publication: true,
7450
- team: true,
7451
- coordinatorGroup: true
7452
- }
7573
+ recipientPolicyLocksHeld: completionRecipientPolicyLocksHeld(actorIds)
7453
7574
  });
7454
7575
  outcome = "applied";
7455
- })))) ? outcome : "claimed";
7576
+ })) ? outcome : "claimed";
7456
7577
  }
7457
7578
  async function reconcileCompletions(store, groups, reconciliationOptions = {}) {
7579
+ const { handledGroupIds, handleFailure, reportFailure } = completionFailureHandlers(reconciliationOptions);
7458
7580
  if (!completionDependencies || groups.length === 0) return;
7459
7581
  let authorization;
7460
7582
  try {
7461
7583
  authorization = currentCompletionAuthorization();
7462
7584
  } catch (error) {
7463
- throw new Error(completionApiError(error));
7585
+ throw new Error(completionApiError(error), { cause: error });
7464
7586
  }
7465
7587
  if (!authorization) return;
7466
7588
  const { config, remoteUrl } = authorization;
@@ -7482,30 +7604,25 @@ function teamSetupRoutes(options) {
7482
7604
  records = await listCompletionRecords(scopedGroupIds);
7483
7605
  } catch (error) {
7484
7606
  if (isUnsupportedCompletionQuery(error)) records = [];
7485
- else if (reconciliationOptions.isolateApplyFailures && isUnattributableCompletionBatchError(error)) records = await listCompletionRecordsPerGroup(scopedGroupIds, listCompletionRecords);
7607
+ else if (reconciliationOptions.isolateApplyFailures && isUnattributableCompletionBatchError(error)) records = await listCompletionRecordsPerGroup(scopedGroupIds, listCompletionRecords, groupCompletionFailureHandler(groupById, handleFailure), error);
7486
7608
  else throw error;
7487
7609
  }
7488
7610
  const freshGroupByKey = /* @__PURE__ */ new Map();
7489
7611
  if (records.length > 0) try {
7490
7612
  const onlyGroup = scopedGroups.length === 1 ? scopedGroups[0] : void 0;
7491
- const freshGroups = onlyGroup ? [await loadFreshGroupSnapshot(onlyGroup, remoteUrl, reconciliationDeadlineMs)] : await loadedSnapshots(void 0, reconciliationDeadlineMs);
7492
- for (const freshGroup of freshGroups) {
7493
- if (!freshGroup) continue;
7494
- const key = freshGroupKey(freshGroup);
7495
- if (freshGroupByKey.has(key)) throw new Error("team_setup_completion_invalid");
7496
- freshGroupByKey.set(key, freshGroup);
7497
- }
7613
+ addFreshCompletionGroups(freshGroupByKey, onlyGroup ? [await loadFreshGroupSnapshot(onlyGroup, remoteUrl, reconciliationDeadlineMs)] : await loadedSnapshots(void 0, reconciliationDeadlineMs), freshGroupKey);
7498
7614
  } catch (error) {
7499
7615
  for (const record of records) {
7500
7616
  const group = groupById.get(record.group_id);
7501
7617
  if (!group || !belongsToGroupCandidate(record, group)) continue;
7618
+ reportFailure(group, error);
7502
7619
  try {
7503
7620
  validateLegacyTeamSetupCompletionManifestBinding(record.manifest, {
7504
7621
  coordinatorId: group.coordinatorId,
7505
7622
  groupId: group.groupId
7506
7623
  });
7507
7624
  } catch (bindingError) {
7508
- if (!reconciliationOptions.isolateApplyFailures) throw bindingError;
7625
+ handleFailure(group, bindingError);
7509
7626
  continue;
7510
7627
  }
7511
7628
  let canonicalManifest;
@@ -7515,16 +7632,17 @@ function teamSetupRoutes(options) {
7515
7632
  groupId: group.groupId
7516
7633
  });
7517
7634
  } catch (validationError) {
7635
+ reportFailure(group, validationError);
7518
7636
  try {
7519
7637
  if (!await runCandidateMutation(store.db, legacyTeamCandidateId(group.coordinatorId, group.groupId), () => containLegacyTeamSetupCompletionConflict(store.db, {
7520
7638
  coordinatorId: group.coordinatorId,
7521
7639
  groupId: group.groupId
7522
7640
  }))) {
7523
- if (!reconciliationOptions.isolateApplyFailures) throw validationError;
7641
+ handleFailure(group, validationError);
7524
7642
  continue;
7525
7643
  }
7526
7644
  } catch (containmentError) {
7527
- if (!reconciliationOptions.isolateApplyFailures) throw containmentError;
7645
+ handleFailure(group, containmentError);
7528
7646
  }
7529
7647
  if (!reconciliationOptions.isolateApplyFailures) throw validationError;
7530
7648
  continue;
@@ -7540,13 +7658,12 @@ function teamSetupRoutes(options) {
7540
7658
  groupId: group.groupId
7541
7659
  }));
7542
7660
  } catch (containmentError) {
7543
- if (!reconciliationOptions.isolateApplyFailures) throw containmentError;
7661
+ handleFailure(group, containmentError);
7544
7662
  }
7545
7663
  }
7546
7664
  if (!reconciliationOptions.isolateApplyFailures) throw error;
7547
7665
  return;
7548
7666
  }
7549
- const coordinatorCompletionGroupIds = /* @__PURE__ */ new Set();
7550
7667
  for (const record of records) {
7551
7668
  const group = groupById.get(record.group_id);
7552
7669
  if (!group) throw new Error("team_setup_completion_invalid");
@@ -7557,7 +7674,7 @@ function teamSetupRoutes(options) {
7557
7674
  groupId: group.groupId
7558
7675
  });
7559
7676
  } catch (bindingError) {
7560
- if (!reconciliationOptions.isolateApplyFailures) throw bindingError;
7677
+ handleFailure(group, bindingError);
7561
7678
  continue;
7562
7679
  }
7563
7680
  let canonicalManifest;
@@ -7567,18 +7684,19 @@ function teamSetupRoutes(options) {
7567
7684
  groupId: group.groupId
7568
7685
  });
7569
7686
  } catch (validationError) {
7687
+ reportFailure(group, validationError);
7570
7688
  try {
7571
7689
  await runCandidateMutation(store.db, legacyTeamCandidateId(group.coordinatorId, group.groupId), () => containLegacyTeamSetupCompletionConflict(store.db, {
7572
7690
  coordinatorId: group.coordinatorId,
7573
7691
  groupId: group.groupId
7574
7692
  }));
7575
7693
  } catch (containmentError) {
7576
- if (!reconciliationOptions.isolateApplyFailures) throw containmentError;
7694
+ handleFailure(group, containmentError);
7577
7695
  }
7578
7696
  if (!reconciliationOptions.isolateApplyFailures) throw validationError;
7579
7697
  continue;
7580
7698
  }
7581
- coordinatorCompletionGroupIds.add(record.group_id);
7699
+ handledGroupIds.add(record.group_id);
7582
7700
  try {
7583
7701
  let freshGroup = freshGroupByKey.get(freshGroupKey(group));
7584
7702
  if (!freshGroup && scopedGroups.length > 1) {
@@ -7590,18 +7708,18 @@ function teamSetupRoutes(options) {
7590
7708
  coordinatorId: group.coordinatorId,
7591
7709
  groupId: group.groupId
7592
7710
  }))) {
7593
- if (!reconciliationOptions.isolateApplyFailures) throw new Error("team_setup_completion_invalid");
7711
+ handleFailure(group, /* @__PURE__ */ new Error("team_setup_completion_invalid"));
7594
7712
  continue;
7595
7713
  }
7596
7714
  throw new Error("team_setup_completion_invalid");
7597
7715
  }
7598
7716
  if (await applyCanonicalManifestIfStillAuthorized(store, authorization, group, canonicalManifest, freshGroup.devices) !== "applied") continue;
7599
7717
  } catch (error) {
7600
- if (!reconciliationOptions.isolateApplyFailures) throw error;
7718
+ handleFailure(group, error);
7601
7719
  }
7602
7720
  }
7603
7721
  for (const group of scopedGroups) {
7604
- if (coordinatorCompletionGroupIds.has(group.groupId)) continue;
7722
+ if (handledGroupIds.has(group.groupId)) continue;
7605
7723
  const publicationTimeoutS = remainingCoordinatorTimeoutS(timeoutS, reconciliationDeadlineMs);
7606
7724
  if (publicationTimeoutS == null) break;
7607
7725
  if (!hasCompletedLegacyTeamSetup(store, legacyTeamCandidateId(group.coordinatorId, group.groupId))) continue;
@@ -7648,14 +7766,14 @@ function teamSetupRoutes(options) {
7648
7766
  coordinatorId: group.coordinatorId,
7649
7767
  groupId: group.groupId
7650
7768
  }))) {
7651
- if (!reconciliationOptions.isolateApplyFailures) throw new Error("team_setup_completion_conflict");
7769
+ handleFailure(group, /* @__PURE__ */ new Error("team_setup_completion_conflict"));
7652
7770
  continue;
7653
7771
  }
7654
7772
  } catch (containmentError) {
7655
- if (!reconciliationOptions.isolateApplyFailures) throw containmentError;
7773
+ handleFailure(group, containmentError);
7656
7774
  continue;
7657
7775
  }
7658
- if (!reconciliationOptions.isolateApplyFailures) throw new Error("team_setup_completion_conflict");
7776
+ handleFailure(group, /* @__PURE__ */ new Error("team_setup_completion_conflict"));
7659
7777
  continue;
7660
7778
  }
7661
7779
  try {
@@ -7664,7 +7782,7 @@ function teamSetupRoutes(options) {
7664
7782
  if (await applyCanonicalManifestIfStillAuthorized(store, authorization, group, canonicalManifest, freshGroup.devices) !== "applied") continue;
7665
7783
  } catch (applyError) {
7666
7784
  if (applyError instanceof LegacyTeamSetupAdditiveConvergenceError) {
7667
- if (!reconciliationOptions.isolateApplyFailures) throw applyError;
7785
+ handleFailure(group, applyError);
7668
7786
  continue;
7669
7787
  }
7670
7788
  try {
@@ -7672,19 +7790,19 @@ function teamSetupRoutes(options) {
7672
7790
  coordinatorId: group.coordinatorId,
7673
7791
  groupId: group.groupId
7674
7792
  }))) {
7675
- if (!reconciliationOptions.isolateApplyFailures) throw new Error("team_setup_completion_conflict", { cause: applyError });
7793
+ handleFailure(group, completionConflictError(applyError));
7676
7794
  continue;
7677
7795
  }
7678
7796
  } catch (containmentError) {
7679
- if (!reconciliationOptions.isolateApplyFailures) throw containmentError;
7797
+ handleFailure(group, containmentError);
7680
7798
  continue;
7681
7799
  }
7682
- if (!reconciliationOptions.isolateApplyFailures) throw new Error("team_setup_completion_conflict", { cause: applyError });
7800
+ handleFailure(group, completionConflictError(applyError));
7683
7801
  }
7684
7802
  }
7685
7803
  }
7686
7804
  } catch (error) {
7687
- throw new Error(completionApiError(error));
7805
+ throw new Error(completionApiError(error), { cause: error });
7688
7806
  }
7689
7807
  }
7690
7808
  async function loadedCandidateSnapshots(candidateRef, loadOptions = {}) {
@@ -7718,21 +7836,15 @@ function teamSetupRoutes(options) {
7718
7836
  try {
7719
7837
  groups = await loadedSummarySnapshots();
7720
7838
  } catch (error) {
7721
- const code = apiErrorCode(error);
7722
- return c.json({ error: code }, errorStatus$1(code));
7839
+ const failure = teamSetupFailure(error, `${c.req.method} ${c.req.routePath}`);
7840
+ return c.json({ error: failure.code }, failure.status);
7723
7841
  }
7724
7842
  try {
7725
- const store = options.getStore();
7726
- readPureCandidateViews(store, groups);
7727
- await reconcileCompletions(store, groups, { isolateApplyFailures: true });
7728
- const response = {
7729
- version: TEAM_SETUP_VERSION,
7730
- candidates: readPureCandidateViews(store, groups).map(candidateSummary).filter((candidate) => candidate.status !== "ready")
7731
- };
7843
+ const response = await reconcileSummaryCandidates(options.getStore(), groups, reconcileCompletions);
7732
7844
  return c.json(response);
7733
7845
  } catch (error) {
7734
- const code = apiErrorCode(error);
7735
- return c.json({ error: code }, errorStatus$1(code));
7846
+ const failure = teamSetupFailure(error, `${c.req.method} ${c.req.routePath}`);
7847
+ return c.json({ error: failure.code }, failure.status);
7736
7848
  }
7737
7849
  });
7738
7850
  app.get("/api/sync/team-setup/v1/:candidateRef", async (c) => {
@@ -7778,8 +7890,8 @@ function teamSetupRoutes(options) {
7778
7890
  if (completionGroups) candidate = candidateFromDraft(draft);
7779
7891
  return c.json(detailResponse(store, draft, candidate));
7780
7892
  } catch (error) {
7781
- const code = apiErrorCode(error);
7782
- return c.json({ error: code }, errorStatus$1(code));
7893
+ const failure = teamSetupFailure(error, `${c.req.method} ${c.req.routePath}`);
7894
+ return c.json({ error: failure.code }, failure.status);
7783
7895
  }
7784
7896
  });
7785
7897
  app.put("/api/sync/team-setup/v1/:candidateRef/devices/:deviceRef/assignment", async (c) => {
@@ -7824,8 +7936,8 @@ function teamSetupRoutes(options) {
7824
7936
  releaseMutation();
7825
7937
  }
7826
7938
  } catch (error) {
7827
- const code = apiErrorCode(error);
7828
- return c.json({ error: code }, errorStatus$1(code));
7939
+ const failure = teamSetupFailure(error, `${c.req.method} ${c.req.routePath}`);
7940
+ return c.json({ error: failure.code }, failure.status);
7829
7941
  }
7830
7942
  });
7831
7943
  app.put("/api/sync/team-setup/v1/:candidateRef/devices/:deviceRef/decision", async (c) => {
@@ -7866,8 +7978,8 @@ function teamSetupRoutes(options) {
7866
7978
  releaseMutation();
7867
7979
  }
7868
7980
  } catch (error) {
7869
- const code = apiErrorCode(error);
7870
- return c.json({ error: code }, errorStatus$1(code));
7981
+ const failure = teamSetupFailure(error, `${c.req.method} ${c.req.routePath}`);
7982
+ return c.json({ error: failure.code }, failure.status);
7871
7983
  }
7872
7984
  });
7873
7985
  app.delete("/api/sync/team-setup/v1/:candidateRef/devices/:deviceRef/decision", async (c) => {
@@ -7897,8 +8009,8 @@ function teamSetupRoutes(options) {
7897
8009
  releaseMutation();
7898
8010
  }
7899
8011
  } catch (error) {
7900
- const code = apiErrorCode(error);
7901
- return c.json({ error: code }, errorStatus$1(code));
8012
+ const failure = teamSetupFailure(error, `${c.req.method} ${c.req.routePath}`);
8013
+ return c.json({ error: failure.code }, failure.status);
7902
8014
  }
7903
8015
  });
7904
8016
  app.put("/api/sync/team-setup/v1/:candidateRef/projects/:projectRef/mapping", async (c) => {
@@ -7933,8 +8045,8 @@ function teamSetupRoutes(options) {
7933
8045
  releaseMutation();
7934
8046
  }
7935
8047
  } catch (error) {
7936
- const code = apiErrorCode(error);
7937
- return c.json({ error: code }, errorStatus$1(code));
8048
+ const failure = teamSetupFailure(error, `${c.req.method} ${c.req.routePath}`);
8049
+ return c.json({ error: failure.code }, failure.status);
7938
8050
  }
7939
8051
  });
7940
8052
  app.post("/api/sync/team-setup/v1/:candidateRef/refresh", async (c) => {
@@ -7947,15 +8059,15 @@ function teamSetupRoutes(options) {
7947
8059
  store = options.getStore();
7948
8060
  if (getLegacyTeamSetupDraft(store.db, candidateRef)?.state === "completed" || hasCompletedLegacyTeamSetup(store, candidateRef)) return c.json({ error: "team_setup_confirmation_stale" }, 409);
7949
8061
  } catch (error) {
7950
- const code = apiErrorCode(error);
7951
- return c.json({ error: code }, errorStatus$1(code));
8062
+ const failure = teamSetupFailure(error, `${c.req.method} ${c.req.routePath}`);
8063
+ return c.json({ error: failure.code }, failure.status);
7952
8064
  }
7953
8065
  let groups;
7954
8066
  try {
7955
8067
  groups = await loadMutableCandidateSnapshots(store, candidateRef, () => loadedCandidateSnapshots(candidateRef));
7956
8068
  } catch (error) {
7957
- const code = apiErrorCode(error);
7958
- return c.json({ error: code }, errorStatus$1(code));
8069
+ const failure = teamSetupFailure(error, `${c.req.method} ${c.req.routePath}`);
8070
+ return c.json({ error: failure.code }, failure.status);
7959
8071
  }
7960
8072
  if (groups.filter((group) => legacyTeamCandidateId(group.coordinatorId, group.groupId) === candidateRef).length === 0) return c.json({ error: "team_setup_confirmation_stale" }, 404);
7961
8073
  try {
@@ -7973,8 +8085,8 @@ function teamSetupRoutes(options) {
7973
8085
  releaseMutation();
7974
8086
  }
7975
8087
  } catch (error) {
7976
- const code = apiErrorCode(error);
7977
- return c.json({ error: code }, errorStatus$1(code));
8088
+ const failure = teamSetupFailure(error, `${c.req.method} ${c.req.routePath}`);
8089
+ return c.json({ error: failure.code }, failure.status);
7978
8090
  }
7979
8091
  });
7980
8092
  app.post("/api/sync/team-setup/v1/:candidateRef/finish", async (c) => {
@@ -8046,13 +8158,14 @@ function teamSetupRoutes(options) {
8046
8158
  if (!claimedDraft || claimedDraft.attemptId !== attemptId) return c.json({ error: "team_setup_confirmation_stale" }, 409);
8047
8159
  const publicationDeadlineMs = Date.now() + COORDINATOR_ROSTER_READ_BUDGET_MS;
8048
8160
  releasePublicationMutation = await claimRecipientPolicyPublicationMutation(store.db);
8049
- releaseActorMutations = await claimRecipientPolicyActorMutations(store.db, claimedDraft.devices.flatMap((device) => [...device.decision === "included" && device.targetIdentityId ? [device.targetIdentityId] : [], ...device.existingIdentityId ? [device.existingIdentityId] : []]));
8161
+ const claimedActorIds = finishDraftActorIds(claimedDraft);
8162
+ releaseActorMutations = await claimRecipientPolicyActorMutations(store.db, claimedActorIds);
8050
8163
  return await serializeRecipientPolicyTeamMutation(store.db, deterministicPolicyTeamId(candidateRef), () => serializeRecipientPolicyCoordinatorGroupMutation(store.db, group.groupId, async () => {
8051
8164
  let authorization;
8052
8165
  try {
8053
8166
  authorization = currentCompletionAuthorization();
8054
8167
  } catch (error) {
8055
- throw new Error(completionApiError(error));
8168
+ throw new Error(completionApiError(error), { cause: error });
8056
8169
  }
8057
8170
  if (!completionDependencies || !authorization) throw new Error("team_setup_completion_unavailable");
8058
8171
  if (!authorizesGroup(authorization, group)) throw new Error("team_setup_completion_invalid");
@@ -8143,11 +8256,7 @@ function teamSetupRoutes(options) {
8143
8256
  freshRoster: postPublicationGroup.devices,
8144
8257
  manifest: canonicalManifest,
8145
8258
  expectedDraftManifest: proposedManifest,
8146
- recipientPolicyLocksHeld: {
8147
- publication: true,
8148
- team: true,
8149
- coordinatorGroup: true
8150
- }
8259
+ recipientPolicyLocksHeld: completionRecipientPolicyLocksHeld(claimedActorIds)
8151
8260
  });
8152
8261
  return c.json(finishResponse(candidateRef, result));
8153
8262
  }));