@taskforcehq/taskforce 0.3.328 → 0.3.329
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/Taskforce.module.css +233 -34
- package/dist/TaskforceCore.js +237 -230
- package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.js +1 -1
- package/dist/cli.js +34 -0
- package/dist/cliCloudTargetGuard.d.ts +5 -0
- package/dist/cliCloudTargetGuard.js +11 -0
- package/dist/components/features/AnnotatedAttachmentWorkspace.js +24 -8
- package/dist/components/features/TaskSettings.d.ts +12 -1
- package/dist/components/features/TaskSettings.js +147 -40
- package/dist/components/features/agentCapabilities/AgentCapabilitiesPrototype.d.ts +1 -1
- package/dist/components/features/planning/PlanningModule.js +2 -5
- package/dist/components/features/planning/PlanningTaskOrderList.d.ts +1 -1
- package/dist/components/features/planning/PlanningTaskOrderList.js +17 -6
- package/dist/components/features/planning/planningTaskArrangement.d.ts +1 -0
- package/dist/components/features/planning/planningTaskArrangement.js +5 -5
- package/dist/components/features/taskforceAgentEditorModel.js +3 -1
- package/dist/components/task/TaskCard.d.ts +5 -0
- package/dist/components/task/TaskCard.js +65 -10
- package/dist/components/task/TaskImageReviews.js +14 -5
- package/dist/components/task/TaskKanban.d.ts +6 -1
- package/dist/components/task/TaskKanban.js +152 -6
- package/dist/components/task/TaskList.d.ts +5 -0
- package/dist/components/task/TaskList.js +3 -3
- package/dist/components/ui/PasswordInput.d.ts +6 -0
- package/dist/components/ui/PasswordInput.js +11 -0
- package/dist/components/ui/TopNoticeLayer.js +1 -1
- package/dist/components/views/AppShellHeader.js +32 -11
- package/dist/components/views/PlanComparisonPage.js +12 -0
- package/dist/components/views/StandaloneLayout.js +7 -31
- package/dist/components/views/WidgetView.js +3 -3
- package/dist/components/views/panels/PlanningDrawer.js +5 -12
- package/dist/components/views/standalone/modals/AccountSettingsModal.js +26 -17
- package/dist/config/envSchema.js +12 -0
- package/dist/config/localServiceRuntimeContract.d.ts +13 -0
- package/dist/config/localServiceRuntimeContract.js +135 -0
- package/dist/core/AiProfileService.js +46 -8
- package/dist/core/DeletedTaskLifecycleService.d.ts +1 -0
- package/dist/core/DeletedTaskLifecycleService.js +37 -6
- package/dist/core/TaskAttachmentLinksDurableMutationService.d.ts +3 -2
- package/dist/core/TaskAttachmentLinksDurableMutationService.js +33 -9
- package/dist/core/Taskforce.d.ts +62 -2
- package/dist/core/Taskforce.js +635 -32
- package/dist/core/types.d.ts +6 -0
- package/dist/hooks/sync/useDurableLocalOutboxDrain.d.ts +1 -1
- package/dist/hooks/sync/useDurableTaskCreateMutation.js +1 -1
- package/dist/hooks/sync/useDurableTaskMetadataMutation.d.ts +1 -0
- package/dist/hooks/sync/useDurableTaskMetadataMutation.js +1 -0
- package/dist/hooks/sync/useDurableTaskStatusMutation.d.ts +1 -0
- package/dist/hooks/tasks/taskHttpMutation.js +1 -0
- package/dist/hooks/tasks/useCloudTaskSearch.d.ts +12 -0
- package/dist/hooks/tasks/useCloudTaskSearch.js +71 -0
- package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.d.ts +16 -0
- package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.js +197 -0
- package/dist/hooks/tasks/useTaskEditorNavigation.d.ts +16 -3
- package/dist/hooks/tasks/useTaskEditorNavigation.js +72 -13
- package/dist/hooks/tasks/useTaskFormActions.d.ts +6 -0
- package/dist/hooks/tasks/useTaskFormActions.js +65 -12
- package/dist/hooks/ui/useSettingsModel.d.ts +24 -2
- package/dist/hooks/ui/useSettingsModel.js +13 -2
- package/dist/hooks/ui/useSettingsPersistence.d.ts +12 -1
- package/dist/hooks/ui/useSettingsPersistence.js +74 -47
- package/dist/hooks/useFilterSort.d.ts +7 -3
- package/dist/hooks/useFilterSort.js +15 -5
- package/dist/hooks/useTaskData.d.ts +10 -1
- package/dist/hooks/useTaskData.js +216 -7
- package/dist/hooks/useTaskMutations.d.ts +10 -2
- package/dist/hooks/useTaskMutations.js +223 -43
- package/dist/hooks/useTaskforce.d.ts +37 -9
- package/dist/hooks/useTaskforce.js +349 -39
- package/dist/hooks/useUiNotice.d.ts +4 -0
- package/dist/hooks/useUiNotice.js +4 -0
- package/dist/mcp/adminWorkspaceRegistrar.js +3 -3
- package/dist/mcp/documentAssetRegistrar.js +44 -35
- package/dist/mcp/documentHelpers.d.ts +1 -0
- package/dist/mcp/documentHelpers.js +7 -3
- package/dist/mcp/runtime.js +172 -42
- package/dist/mcp/taskPlanningRegistrar.js +41 -38
- package/dist/mcp/toolCallCompatibility.js +38 -1
- package/dist/mcp/toolCatalog.d.ts +1 -0
- package/dist/migrations/taskSchemaMigrations.js +12 -0
- package/dist/runtime/appGateDefinitions.d.ts +30 -6
- package/dist/runtime/appGateDefinitions.js +6 -6
- package/dist/runtime/appGates.d.ts +12 -13
- package/dist/runtime/appGates.js +29 -13
- package/dist/runtime/nodeAppGates.d.ts +8 -0
- package/dist/runtime/nodeAppGates.js +27 -0
- package/dist/server/cloudCollectionRead.d.ts +1 -1
- package/dist/server/cloudCollectionRead.js +2 -2
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.js +15 -3
- package/dist/server/localServiceLease.d.ts +3 -0
- package/dist/server/localServiceLease.js +9 -1
- package/dist/server/localWorkspaceSyncServerRuntime.js +10 -3
- package/dist/server/rateLimit.d.ts +1 -0
- package/dist/server/rateLimit.js +4 -0
- package/dist/server/realtimeSyncWs.js +36 -12
- package/dist/server/routes/admin.js +1 -0
- package/dist/server/routes/agentRoles.js +3 -2
- package/dist/server/routes/agentSkills.js +3 -2
- package/dist/server/routes/agents.js +118 -16
- package/dist/server/routes/annotatedAttachments.js +3 -2
- package/dist/server/routes/auth.js +3 -1
- package/dist/server/routes/durableTaskHttpRouters.d.ts +9 -2
- package/dist/server/routes/localService.js +2 -0
- package/dist/server/routes/primitives.d.ts +2 -0
- package/dist/server/routes/syncAuxRoutes.js +5 -2
- package/dist/server/routes/syncPullApplyRoutes.js +23 -4
- package/dist/server/routes/syncV3FeedRoutes.js +18 -16
- package/dist/server/routes/syncV3LocalCaptureRoutes.js +28 -2
- package/dist/server/routes/syncV3LocalFeedApplyRoutes.d.ts +1 -0
- package/dist/server/routes/syncV3LocalFeedApplyRoutes.js +26 -0
- package/dist/server/routes/syncV3OperationRoutes.js +10 -0
- package/dist/server/routes/tasks.js +103 -11
- package/dist/server/routes/workspaces.js +43 -1
- package/dist/server/workspaceDeletionAdmission.d.ts +23 -0
- package/dist/server/workspaceDeletionAdmission.js +50 -0
- package/dist/service/localServiceCli.js +16 -0
- package/dist/service/localServiceClientLifecycle.js +36 -10
- package/dist/services/codexAppServerModelGateway.d.ts +112 -0
- package/dist/services/codexAppServerModelGateway.js +438 -0
- package/dist/services/taskforceAgentMcpBridge.d.ts +7 -1
- package/dist/services/taskforceAgentMcpBridge.js +23 -3
- package/dist/shared/taskforceAgentDefinition.js +7 -1
- package/dist/shared/taskforceAgentModels.d.ts +1 -0
- package/dist/shared/taskforceAgentModels.js +30 -1
- package/dist/storage/postgresAdapter.d.ts +20 -3
- package/dist/storage/postgresAdapter.js +106 -14
- package/dist/storage/postgresWorker.js +13 -4
- package/dist/storage/postgresWorkerProtocol.d.ts +29 -0
- package/dist/storage/postgresWorkerProtocol.js +30 -0
- package/dist/sync/cloudSyncApi.d.ts +4 -1
- package/dist/sync/cloudSyncApi.js +7 -2
- package/dist/sync/contentSyncState.d.ts +1 -1
- package/dist/sync/coordinator/localSyncExecutionPermitStore.d.ts +1 -0
- package/dist/sync/coordinator/localSyncExecutionPermitStore.js +7 -1
- package/dist/sync/coordinator/localWorkspaceSyncRunner.js +6 -2
- package/dist/sync/engine/workspaceSyncEngineBrowserGatewayRemoteServices.js +20 -2
- package/dist/sync/engine/workspaceSyncEngineLocalServices.d.ts +4 -0
- package/dist/sync/engine/workspaceSyncEngineLocalServices.js +11 -0
- package/dist/sync/engine/workspaceSyncEngineRemoteServices.d.ts +11 -0
- package/dist/sync/engine/workspaceSyncEngineRemoteServices.js +2 -1
- package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.js +31 -4
- package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.d.ts +3 -1
- package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +25 -8
- package/dist/sync/engine/workspaceSyncEngineTransfers.d.ts +1 -1
- package/dist/sync/engine/workspaceSyncEngineTransfers.js +8 -3
- package/dist/sync/syncService.d.ts +2 -0
- package/dist/sync/syncService.js +4 -1
- package/dist/sync/v3/combinedFeedCapability.js +4 -0
- package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.d.ts +2 -0
- package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.js +11 -1
- package/dist/sync/v3/durableTaskChecklistMutationRouter.d.ts +2 -0
- package/dist/sync/v3/durableTaskChecklistMutationRouter.js +4 -0
- package/dist/sync/v3/durableTaskHttpBulkMutationRouter.d.ts +1 -0
- package/dist/sync/v3/durableTaskHttpBulkMutationRouter.js +30 -8
- package/dist/sync/v3/durableTaskHttpRootMutationRouter.d.ts +5 -3
- package/dist/sync/v3/durableTaskHttpRootMutationRouter.js +27 -2
- package/dist/sync/v3/localTaskAttachmentLinksOutboxService.d.ts +2 -0
- package/dist/sync/v3/localTaskAttachmentLinksOutboxService.js +47 -7
- package/dist/sync/v3/localTaskCreateOutboxService.js +15 -6
- package/dist/sync/v3/localTaskMetadataClient.d.ts +1 -0
- package/dist/sync/v3/localTaskMetadataClient.js +1 -0
- package/dist/sync/v3/localTaskMetadataOutboxHandler.js +5 -1
- package/dist/sync/v3/localTaskMetadataOutboxService.d.ts +2 -0
- package/dist/sync/v3/localTaskMetadataOutboxService.js +7 -0
- package/dist/sync/v3/localTaskRestoreOutboxService.js +14 -6
- package/dist/sync/v3/localTaskStatusClient.d.ts +1 -0
- package/dist/sync/v3/localTaskStatusClient.js +6 -1
- package/dist/sync/v3/localTaskStatusOutboxService.d.ts +2 -0
- package/dist/sync/v3/localTaskStatusOutboxService.js +54 -13
- package/dist/sync/v3/syncDurabilityStore.d.ts +7 -0
- package/dist/sync/v3/syncDurabilityStore.js +31 -11
- package/dist/sync/v3/taskAttachmentLinksMutationService.d.ts +6 -4
- package/dist/sync/v3/taskAttachmentLinksMutationService.js +19 -10
- package/dist/sync/v3/taskChecklistMutationService.d.ts +4 -2
- package/dist/sync/v3/taskChecklistMutationService.js +4 -0
- package/dist/sync/v3/taskCreateMutationService.d.ts +2 -2
- package/dist/sync/v3/taskCreateMutationService.js +7 -4
- package/dist/sync/v3/taskMetadataMutationService.d.ts +3 -0
- package/dist/sync/v3/taskMetadataMutationService.js +4 -0
- package/dist/sync/v3/taskRestoreMutationService.d.ts +2 -2
- package/dist/sync/v3/taskRestoreMutationService.js +7 -4
- package/dist/sync/v3/taskStatusMutationService.d.ts +2 -0
- package/dist/sync/v3/taskStatusMutationService.js +4 -0
- package/dist/sync/v3/workflowAssignmentSync.d.ts +1 -0
- package/dist/sync/v3/workflowAssignmentSync.js +3 -0
- package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.d.ts +1 -1
- package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.js +13 -3
- package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.d.ts +11 -0
- package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.js +27 -10
- package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.d.ts +2 -1
- package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.js +52 -10
- package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.js +9 -1
- package/dist/sync/v3/workspaceSyncV3CombinedFeedOrchestrator.js +8 -3
- package/dist/sync/v3/workspaceSyncV3CombinedLocalApply.js +51 -10
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.d.ts +7 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.js +30 -18
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.d.ts +9 -4
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.js +98 -47
- package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.d.ts +10 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.js +58 -21
- package/dist/sync/v3/workspaceSyncV3CombinedWireContract.d.ts +3 -1
- package/dist/sync/v3/workspaceSyncV3CombinedWireContract.js +18 -0
- package/dist/sync/v3/workspaceSyncV3CoverageRegistry.js +6 -0
- package/dist/sync/v3/workspaceSyncV3FeedProfile.d.ts +1 -1
- package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.d.ts +1 -0
- package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.js +23 -10
- package/dist/sync/v3/workspaceSyncV3NestedTaskApply.d.ts +3 -0
- package/dist/sync/v3/workspaceSyncV3NestedTaskApply.js +64 -13
- package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.d.ts +9 -0
- package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.js +26 -0
- package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.d.ts +15 -5
- package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.js +50 -14
- package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.d.ts +2 -1
- package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.js +11 -3
- package/dist/sync/v3/workspaceSyncV3OperationProtocol.d.ts +2 -0
- package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.d.ts +2 -0
- package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.js +19 -7
- package/dist/sync/v3/workspaceSyncV3TaskCommentAudit.js +9 -2
- package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.d.ts +7 -0
- package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.js +37 -0
- package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.d.ts +6 -0
- package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.js +9 -0
- package/dist/sync/workspacePullFeed.js +2 -1
- package/dist/sync/workspaceRepair.d.ts +3 -0
- package/dist/sync/workspaceRepair.js +67 -6
- package/dist/types.d.ts +47 -1
- package/dist/types.js +6 -0
- package/dist/ui/assets/{AiIdentityRosterCard-MZs7lVED.js → AiIdentityRosterCard-BZM4aQnM.js} +1 -1
- package/dist/ui/assets/AiProfilesModule-BbAEWtHH.js +1 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-B68Wg-RV.js +3 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-TzYu7pkG.css +1 -0
- package/dist/ui/assets/{AssetTraySortControl-Kf1pelSy.js → AssetTraySortControl-C8Rztyal.js} +1 -1
- package/dist/ui/assets/{ContextAttachmentManager-B8boOs6Q.js → ContextAttachmentManager-Cj3c7X9y.js} +2 -2
- package/dist/ui/assets/{DocumentWorkspace-DXH4XUsB.js → DocumentWorkspace-B5uvzems.js} +1 -1
- package/dist/ui/assets/{EntityActivityTimeline-BtSTq0ON.js → EntityActivityTimeline-BVFvCB5R.js} +1 -1
- package/dist/ui/assets/PlanningModule-B5DWQOGz.js +1 -0
- package/dist/ui/assets/PlansPage-AY4cGWco.js +1 -0
- package/dist/ui/assets/TaskContextUpload-DZxTVesW.js +1 -0
- package/dist/ui/assets/TaskSettings-BeWAuyZj.js +12 -0
- package/dist/ui/assets/{TaskforceAgentsModule-BazdUwxZ.js → TaskforceAgentsModule-BifCYtjR.js} +6 -6
- package/dist/ui/assets/{WorkflowManagerModule-DWFspC-o.js → WorkflowManagerModule-DEr5di_r.js} +1 -1
- package/dist/ui/assets/index-I5zhdtgt.js +7 -0
- package/dist/ui/assets/index-VRFsx3wz.css +1 -0
- package/dist/ui/assets/{vendor-icons-BkFLXavV.js → vendor-icons-D9Lpw-j4.js} +1 -1
- package/dist/ui/index.html +3 -3
- package/dist/utils/taskActivity.d.ts +3 -2
- package/dist/utils/taskActivity.js +19 -2
- package/dist/utils/taskEditorReconciliation.d.ts +40 -0
- package/dist/utils/taskEditorReconciliation.js +217 -0
- package/dist/utils/taskNormalization.d.ts +1 -0
- package/dist/utils/taskNormalization.js +39 -0
- package/dist/utils/taskSearch.js +2 -2
- package/dist/utils/uiNotice.d.ts +4 -0
- package/package.json +16 -4
- package/dist/ui/assets/AiProfilesModule-C3i0LOxe.js +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-CBRZ8rca.css +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-DVZk5Tln.js +0 -3
- package/dist/ui/assets/PlanningModule-BPVyEa-f.js +0 -1
- package/dist/ui/assets/PlansPage-ChqgxALc.js +0 -1
- package/dist/ui/assets/TaskContextUpload-CB3ol0sN.js +0 -1
- package/dist/ui/assets/TaskSettings-g4ECKNOz.js +0 -12
- package/dist/ui/assets/index-BUplSsv_.js +0 -7
- package/dist/ui/assets/index-gz2EXuoK.css +0 -1
|
@@ -8,12 +8,13 @@ import { serializeTaskRootForSync, projectWorkspaceSyncV3TaskRootJournalRow } fr
|
|
|
8
8
|
import { projectWorkspaceSyncV3TaxonomyJournalRow } from './workspaceSyncV3TaxonomyFeedProjection.js';
|
|
9
9
|
import { projectWorkspaceSyncV3WorkstreamJournalRow } from './workspaceSyncV3WorkstreamProjection.js';
|
|
10
10
|
import { buildWorkspaceSyncV3NestedTaskRepairCandidates, } from './workspaceSyncV3NestedTaskRepairSnapshot.js';
|
|
11
|
-
import { projectWorkspaceSyncV3NestedTaskJournalRow } from './workspaceSyncV3NestedTaskProjection.js';
|
|
11
|
+
import { projectWorkspaceSyncV3NestedTaskJournalRow, projectWorkspaceSyncV3NestedTaskV2JournalRow, } from './workspaceSyncV3NestedTaskProjection.js';
|
|
12
12
|
import { validateWorkspaceSyncV3NestedCoverageFeedEntry, WORKSPACE_SYNC_V3_NESTED_COVERAGE_PROFILE, } from './workspaceSyncV3NestedCoverage.js';
|
|
13
13
|
import { serializeWorkflowExecutionEventSyncPayload, serializeWorkflowExecutionRootSyncPayload, serializeWorkflowPublishedDefinitionSyncPayload, } from './workflowRuntimeSync.js';
|
|
14
14
|
import { projectWorkspaceSyncV3WorkflowRuntimeJournalRow, } from './workspaceSyncV3WorkflowRuntimeProjection.js';
|
|
15
15
|
import { validateWorkspaceSyncV3WorkflowCoverageFeedEntry, WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_PROFILE, } from './workspaceSyncV3WorkflowCoverage.js';
|
|
16
16
|
import { validateWorkspaceSyncV3PlanningOrderCoverageFeedEntry, WORKSPACE_SYNC_V3_PLANNING_ORDER_COVERAGE_PROFILE, } from './workspaceSyncV3PlanningOrderCoverage.js';
|
|
17
|
+
import { validateWorkspaceSyncV3TaskCoverCoverageFeedEntry, WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_PROFILE, } from './workspaceSyncV3TaskCoverCoverage.js';
|
|
17
18
|
import { projectWorkspaceSyncV3WorkstreamTaskOrderJournalRow } from './workspaceSyncV3WorkstreamTaskOrderProjection.js';
|
|
18
19
|
import { serializeWorkstreamTaskOrderForSync } from './workstreamTaskOrderSync.js';
|
|
19
20
|
import { serializeTaxonomyStateForSync } from './taxonomySyncPayload.js';
|
|
@@ -28,6 +29,8 @@ const WORKFLOW_PROJECTION_RANK = new Map(WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_PRO
|
|
|
28
29
|
.map((projection, index) => [projection.projectionId, index]));
|
|
29
30
|
const PLANNING_ORDER_PROJECTION_RANK = new Map(WORKSPACE_SYNC_V3_PLANNING_ORDER_COVERAGE_PROFILE.projections
|
|
30
31
|
.map((projection, index) => [projection.projectionId, index]));
|
|
32
|
+
const TASK_COVER_PROJECTION_RANK = new Map(WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_PROFILE.projections
|
|
33
|
+
.map((projection, index) => [projection.projectionId, index]));
|
|
31
34
|
export class WorkspaceSyncV3CombinedRepairBaselineRequiredError extends Error {
|
|
32
35
|
missing;
|
|
33
36
|
code = 'WORKSPACE_SYNC_V3_COMBINED_REPAIR_BASELINE_REQUIRED';
|
|
@@ -42,11 +45,13 @@ function compareCodeUnits(left, right) {
|
|
|
42
45
|
function projectionRank(entry, coverage) {
|
|
43
46
|
const ranks = coverage === 'workflow'
|
|
44
47
|
? WORKFLOW_PROJECTION_RANK
|
|
45
|
-
: coverage === '
|
|
46
|
-
?
|
|
47
|
-
: coverage === '
|
|
48
|
-
?
|
|
49
|
-
:
|
|
48
|
+
: coverage === 'task-cover'
|
|
49
|
+
? TASK_COVER_PROJECTION_RANK
|
|
50
|
+
: coverage === 'planning-order'
|
|
51
|
+
? PLANNING_ORDER_PROJECTION_RANK
|
|
52
|
+
: coverage === 'nested'
|
|
53
|
+
? NESTED_PROJECTION_RANK
|
|
54
|
+
: COMBINED_PROJECTION_RANK;
|
|
50
55
|
const rank = ranks.get(entry.projection);
|
|
51
56
|
if (rank === undefined)
|
|
52
57
|
throw new Error(`Unsupported combined repair projection: ${entry.projection}.`);
|
|
@@ -151,8 +156,7 @@ function listLiveEvents(core, workspaceId, liveEntityIds) {
|
|
|
151
156
|
cursor = { watermark: last.createdAt, id: eventCursorId(last) };
|
|
152
157
|
}
|
|
153
158
|
}
|
|
154
|
-
|
|
155
|
-
export function listWorkspaceSyncV3NestedRepairCandidates(core, workspaceId) {
|
|
159
|
+
function listNestedRepairCandidates(core, workspaceId, attachmentProjection) {
|
|
156
160
|
const startedAt = Date.now();
|
|
157
161
|
const tasks = listTasks(core, workspaceId);
|
|
158
162
|
const tasksCompletedAt = Date.now();
|
|
@@ -185,6 +189,7 @@ export function listWorkspaceSyncV3NestedRepairCandidates(core, workspaceId) {
|
|
|
185
189
|
tasks,
|
|
186
190
|
events,
|
|
187
191
|
attachmentLinksByTaskId,
|
|
192
|
+
attachmentProjection,
|
|
188
193
|
}),
|
|
189
194
|
];
|
|
190
195
|
const completedAt = Date.now();
|
|
@@ -210,6 +215,14 @@ export function listWorkspaceSyncV3NestedRepairCandidates(core, workspaceId) {
|
|
|
210
215
|
}
|
|
211
216
|
return candidates;
|
|
212
217
|
}
|
|
218
|
+
/** Candidate v4 inventory. The coverage-v3 inventory above intentionally remains unchanged. */
|
|
219
|
+
export function listWorkspaceSyncV3NestedRepairCandidates(core, workspaceId) {
|
|
220
|
+
return listNestedRepairCandidates(core, workspaceId, 'task-attachment-links/full-v1');
|
|
221
|
+
}
|
|
222
|
+
/** Candidate v7 inventory. It is the v4 family with attachment-link schema v2. */
|
|
223
|
+
export function listWorkspaceSyncV3TaskCoverRepairCandidates(core, workspaceId) {
|
|
224
|
+
return listNestedRepairCandidates(core, workspaceId, 'task-attachment-links/full-v2');
|
|
225
|
+
}
|
|
213
226
|
/** Candidate v5 inventory. Coverage-v3/v4 inventories intentionally remain unchanged. */
|
|
214
227
|
export function listWorkspaceSyncV3WorkflowRepairCandidates(core, workspaceId) {
|
|
215
228
|
const workflowStore = new WorkflowStore(core.getDatabaseAdapter(), core.getTenantId());
|
|
@@ -380,7 +393,7 @@ function taskEntry(candidate, row, priorFullRow) {
|
|
|
380
393
|
return { ...projected, mutationKind, payload: candidate.payload,
|
|
381
394
|
payloadFingerprint: fingerprintWorkspaceSyncPayload(candidate.payload) };
|
|
382
395
|
}
|
|
383
|
-
function entry(candidate, row, taskFullProvenance) {
|
|
396
|
+
function entry(candidate, row, taskFullProvenance, taskCoverCoverage = false) {
|
|
384
397
|
if (candidate.domain === 'workstream-task-order') {
|
|
385
398
|
const projected = projectWorkspaceSyncV3WorkstreamTaskOrderJournalRow(row);
|
|
386
399
|
if (!projected
|
|
@@ -401,7 +414,9 @@ function entry(candidate, row, taskFullProvenance) {
|
|
|
401
414
|
}
|
|
402
415
|
if (candidate.domain === 'task-comments' || candidate.domain === 'task-checklist'
|
|
403
416
|
|| candidate.domain === 'task-attachment-links' || candidate.domain === 'entity-event') {
|
|
404
|
-
const projected =
|
|
417
|
+
const projected = taskCoverCoverage && candidate.domain === 'task-attachment-links'
|
|
418
|
+
? projectWorkspaceSyncV3NestedTaskV2JournalRow(row)
|
|
419
|
+
: projectWorkspaceSyncV3NestedTaskJournalRow(row);
|
|
405
420
|
if (!projected) {
|
|
406
421
|
throw new Error(`${candidate.domain} repair revision does not match canonical state: ${candidate.entityId}.`);
|
|
407
422
|
}
|
|
@@ -475,22 +490,26 @@ export function buildWorkspaceSyncV3CombinedRepairSnapshotFromLockedCandidates(i
|
|
|
475
490
|
.map((candidate) => candidate.entityId);
|
|
476
491
|
const taskFullProvenance = readTaskFullProvenanceRows({ db, tenantId, workspaceId, taskIds: remappedTaskIds });
|
|
477
492
|
const provenanceCompletedAt = Date.now();
|
|
478
|
-
const entries = inventory.map((candidate) => entry(candidate, rows.get(`${candidate.domain}\0${candidate.entityId}`), taskFullProvenance));
|
|
493
|
+
const entries = inventory.map((candidate) => entry(candidate, rows.get(`${candidate.domain}\0${candidate.entityId}`), taskFullProvenance, input.taskCoverCoverage === true));
|
|
479
494
|
const entriesCompletedAt = Date.now();
|
|
480
495
|
const coverage = input.workflowCoverage
|
|
481
496
|
? 'workflow'
|
|
482
|
-
: input.
|
|
483
|
-
? '
|
|
484
|
-
: input.
|
|
485
|
-
? '
|
|
486
|
-
:
|
|
497
|
+
: input.taskCoverCoverage
|
|
498
|
+
? 'task-cover'
|
|
499
|
+
: input.planningOrderCoverage
|
|
500
|
+
? 'planning-order'
|
|
501
|
+
: input.nestedCoverage
|
|
502
|
+
? 'nested'
|
|
503
|
+
: 'combined';
|
|
487
504
|
entries.forEach(coverage === 'workflow'
|
|
488
505
|
? validateWorkspaceSyncV3WorkflowCoverageFeedEntry
|
|
489
|
-
: coverage === '
|
|
490
|
-
?
|
|
491
|
-
: coverage === '
|
|
492
|
-
?
|
|
493
|
-
:
|
|
506
|
+
: coverage === 'task-cover'
|
|
507
|
+
? validateWorkspaceSyncV3TaskCoverCoverageFeedEntry
|
|
508
|
+
: coverage === 'planning-order'
|
|
509
|
+
? validateWorkspaceSyncV3PlanningOrderCoverageFeedEntry
|
|
510
|
+
: coverage === 'nested'
|
|
511
|
+
? validateWorkspaceSyncV3NestedCoverageFeedEntry
|
|
512
|
+
: validateWorkspaceSyncV3CombinedFeedEntry);
|
|
494
513
|
const validationCompletedAt = Date.now();
|
|
495
514
|
if (entries.some((candidate) => BigInt(candidate.sequence) > BigInt(snapshotSequence))) {
|
|
496
515
|
throw new Error('Combined repair entry exceeds the locked snapshot sequence.');
|
|
@@ -564,3 +583,21 @@ export function buildWorkspaceSyncV3PlanningOrderRepairSnapshot(input) {
|
|
|
564
583
|
});
|
|
565
584
|
})();
|
|
566
585
|
}
|
|
586
|
+
export function buildWorkspaceSyncV3TaskCoverRepairSnapshot(input) {
|
|
587
|
+
const workspaceId = String(input.workspaceId || '').trim();
|
|
588
|
+
if (!workspaceId)
|
|
589
|
+
throw new Error('Workspace id is required.');
|
|
590
|
+
const tenantId = input.core.getTenantId();
|
|
591
|
+
const db = input.core.getDatabaseAdapter();
|
|
592
|
+
return db.transaction(() => {
|
|
593
|
+
const snapshotSequence = lockAndReadHighWatermark(db, tenantId, workspaceId);
|
|
594
|
+
const inventory = listWorkspaceSyncV3TaskCoverRepairCandidates(input.core, workspaceId);
|
|
595
|
+
return buildWorkspaceSyncV3CombinedRepairSnapshotFromLockedCandidates({
|
|
596
|
+
core: input.core,
|
|
597
|
+
workspaceId,
|
|
598
|
+
snapshotSequence,
|
|
599
|
+
inventory,
|
|
600
|
+
taskCoverCoverage: true,
|
|
601
|
+
});
|
|
602
|
+
})();
|
|
603
|
+
}
|
|
@@ -2,6 +2,7 @@ import type { WorkspaceSyncV2ProjectionExclusion } from './workspaceSyncV2Projec
|
|
|
2
2
|
import { WORKSPACE_SYNC_V3_NESTED_COVERAGE_SELECTOR } from './workspaceSyncV3NestedWireContract.js';
|
|
3
3
|
import { WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_SELECTOR } from './workspaceSyncV3WorkflowWireContract.js';
|
|
4
4
|
import { WORKSPACE_SYNC_V3_PLANNING_ORDER_COVERAGE_SELECTOR } from './workspaceSyncV3PlanningOrderWireContract.js';
|
|
5
|
+
import { WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_SELECTOR } from './workspaceSyncV3TaskCoverWireContract.js';
|
|
5
6
|
export declare const WORKSPACE_SYNC_V3_COMBINED_COVERAGE_SELECTOR: Readonly<{
|
|
6
7
|
coverageProfileId: "task-planning-metadata";
|
|
7
8
|
coverageVersion: 3;
|
|
@@ -9,13 +10,14 @@ export declare const WORKSPACE_SYNC_V3_COMBINED_COVERAGE_SELECTOR: Readonly<{
|
|
|
9
10
|
}>;
|
|
10
11
|
export declare const WORKSPACE_SYNC_V3_COMBINED_CAPABILITY_VERSION: 1;
|
|
11
12
|
export declare const WORKSPACE_SYNC_V3_COMBINED_EXCLUDED_V2_PROJECTIONS: readonly ["task/root-v1", "task-relationship/full-v1", "taxonomy/full-v1", "initiative/full-v1", "workstream/full-v1"];
|
|
12
|
-
export type WorkspaceSyncV3CombinedCoverageSelector = typeof WORKSPACE_SYNC_V3_COMBINED_COVERAGE_SELECTOR | typeof WORKSPACE_SYNC_V3_NESTED_COVERAGE_SELECTOR | typeof WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_SELECTOR | typeof WORKSPACE_SYNC_V3_PLANNING_ORDER_COVERAGE_SELECTOR;
|
|
13
|
+
export type WorkspaceSyncV3CombinedCoverageSelector = typeof WORKSPACE_SYNC_V3_COMBINED_COVERAGE_SELECTOR | typeof WORKSPACE_SYNC_V3_NESTED_COVERAGE_SELECTOR | typeof WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_SELECTOR | typeof WORKSPACE_SYNC_V3_PLANNING_ORDER_COVERAGE_SELECTOR | typeof WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_SELECTOR;
|
|
13
14
|
export interface WorkspaceSyncV3CombinedWireContract {
|
|
14
15
|
coverage: WorkspaceSyncV3CombinedCoverageSelector;
|
|
15
16
|
excludedProjections: readonly WorkspaceSyncV2ProjectionExclusion[];
|
|
16
17
|
nestedWriterPrerequisitesRequired: boolean;
|
|
17
18
|
workflowWriterPrerequisitesRequired: boolean;
|
|
18
19
|
planningOrderWriterPrerequisitesRequired: boolean;
|
|
20
|
+
taskCoverProjectionRequired: boolean;
|
|
19
21
|
}
|
|
20
22
|
export declare function resolveWorkspaceSyncV3CombinedWireContract(input: {
|
|
21
23
|
coverageProfileId: unknown;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { WORKSPACE_SYNC_V3_NESTED_COVERAGE_SELECTOR, WORKSPACE_SYNC_V3_NESTED_EXCLUDED_V2_PROJECTIONS, } from './workspaceSyncV3NestedWireContract.js';
|
|
2
2
|
import { WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_SELECTOR, WORKSPACE_SYNC_V3_WORKFLOW_EXCLUDED_V2_PROJECTIONS, } from './workspaceSyncV3WorkflowWireContract.js';
|
|
3
3
|
import { WORKSPACE_SYNC_V3_PLANNING_ORDER_COVERAGE_SELECTOR, WORKSPACE_SYNC_V3_PLANNING_ORDER_EXCLUDED_V2_PROJECTIONS, } from './workspaceSyncV3PlanningOrderWireContract.js';
|
|
4
|
+
import { WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_SELECTOR, WORKSPACE_SYNC_V3_TASK_COVER_EXCLUDED_V2_PROJECTIONS, } from './workspaceSyncV3TaskCoverWireContract.js';
|
|
4
5
|
export const WORKSPACE_SYNC_V3_COMBINED_COVERAGE_SELECTOR = Object.freeze({
|
|
5
6
|
coverageProfileId: 'task-planning-metadata',
|
|
6
7
|
coverageVersion: 3,
|
|
@@ -27,6 +28,7 @@ export function resolveWorkspaceSyncV3CombinedWireContract(input) {
|
|
|
27
28
|
nestedWriterPrerequisitesRequired: false,
|
|
28
29
|
workflowWriterPrerequisitesRequired: false,
|
|
29
30
|
planningOrderWriterPrerequisitesRequired: false,
|
|
31
|
+
taskCoverProjectionRequired: false,
|
|
30
32
|
};
|
|
31
33
|
}
|
|
32
34
|
if (profileId === WORKSPACE_SYNC_V3_NESTED_COVERAGE_SELECTOR.coverageProfileId
|
|
@@ -38,6 +40,7 @@ export function resolveWorkspaceSyncV3CombinedWireContract(input) {
|
|
|
38
40
|
nestedWriterPrerequisitesRequired: true,
|
|
39
41
|
workflowWriterPrerequisitesRequired: false,
|
|
40
42
|
planningOrderWriterPrerequisitesRequired: false,
|
|
43
|
+
taskCoverProjectionRequired: false,
|
|
41
44
|
};
|
|
42
45
|
}
|
|
43
46
|
if (profileId === WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_SELECTOR.coverageProfileId
|
|
@@ -49,6 +52,7 @@ export function resolveWorkspaceSyncV3CombinedWireContract(input) {
|
|
|
49
52
|
nestedWriterPrerequisitesRequired: true,
|
|
50
53
|
workflowWriterPrerequisitesRequired: true,
|
|
51
54
|
planningOrderWriterPrerequisitesRequired: false,
|
|
55
|
+
taskCoverProjectionRequired: false,
|
|
52
56
|
};
|
|
53
57
|
}
|
|
54
58
|
if (profileId === WORKSPACE_SYNC_V3_PLANNING_ORDER_COVERAGE_SELECTOR.coverageProfileId
|
|
@@ -60,6 +64,19 @@ export function resolveWorkspaceSyncV3CombinedWireContract(input) {
|
|
|
60
64
|
nestedWriterPrerequisitesRequired: true,
|
|
61
65
|
workflowWriterPrerequisitesRequired: false,
|
|
62
66
|
planningOrderWriterPrerequisitesRequired: true,
|
|
67
|
+
taskCoverProjectionRequired: false,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
if (profileId === WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_SELECTOR.coverageProfileId
|
|
71
|
+
&& version === WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_SELECTOR.coverageVersion
|
|
72
|
+
&& digest === WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_SELECTOR.coverageDigest) {
|
|
73
|
+
return {
|
|
74
|
+
coverage: WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_SELECTOR,
|
|
75
|
+
excludedProjections: WORKSPACE_SYNC_V3_TASK_COVER_EXCLUDED_V2_PROJECTIONS,
|
|
76
|
+
nestedWriterPrerequisitesRequired: true,
|
|
77
|
+
workflowWriterPrerequisitesRequired: false,
|
|
78
|
+
planningOrderWriterPrerequisitesRequired: false,
|
|
79
|
+
taskCoverProjectionRequired: true,
|
|
63
80
|
};
|
|
64
81
|
}
|
|
65
82
|
return null;
|
|
@@ -70,6 +87,7 @@ export function resolveWorkspaceSyncV3CombinedCoverageForExclusions(exclusions)
|
|
|
70
87
|
WORKSPACE_SYNC_V3_NESTED_COVERAGE_SELECTOR,
|
|
71
88
|
WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_SELECTOR,
|
|
72
89
|
WORKSPACE_SYNC_V3_PLANNING_ORDER_COVERAGE_SELECTOR,
|
|
90
|
+
WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_SELECTOR,
|
|
73
91
|
]) {
|
|
74
92
|
const contract = resolveWorkspaceSyncV3CombinedWireContract(coverage);
|
|
75
93
|
if (exclusions.length === contract.excludedProjections.length
|
|
@@ -2,6 +2,7 @@ import { WORKSPACE_SYNC_V3_COMBINED_COVERAGE_POLICY, WORKSPACE_SYNC_V3_COMBINED_
|
|
|
2
2
|
import { WORKSPACE_SYNC_V3_NESTED_COVERAGE_POLICY, WORKSPACE_SYNC_V3_NESTED_COVERAGE_PROFILE, validateWorkspaceSyncV3NestedCoverageFeedEntry, } from './workspaceSyncV3NestedCoverage.js';
|
|
3
3
|
import { WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_POLICY, WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_PROFILE, validateWorkspaceSyncV3WorkflowCoverageFeedEntry, } from './workspaceSyncV3WorkflowCoverage.js';
|
|
4
4
|
import { WORKSPACE_SYNC_V3_PLANNING_ORDER_COVERAGE_POLICY, WORKSPACE_SYNC_V3_PLANNING_ORDER_COVERAGE_PROFILE, validateWorkspaceSyncV3PlanningOrderCoverageFeedEntry, } from './workspaceSyncV3PlanningOrderCoverage.js';
|
|
5
|
+
import { WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_POLICY, WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_PROFILE, validateWorkspaceSyncV3TaskCoverCoverageFeedEntry, } from './workspaceSyncV3TaskCoverCoverage.js';
|
|
5
6
|
export const WORKSPACE_SYNC_V3_REGISTERED_COVERAGES = Object.freeze([
|
|
6
7
|
Object.freeze({
|
|
7
8
|
profile: WORKSPACE_SYNC_V3_COMBINED_COVERAGE_PROFILE,
|
|
@@ -23,6 +24,11 @@ export const WORKSPACE_SYNC_V3_REGISTERED_COVERAGES = Object.freeze([
|
|
|
23
24
|
policy: WORKSPACE_SYNC_V3_PLANNING_ORDER_COVERAGE_POLICY,
|
|
24
25
|
validateEntry: validateWorkspaceSyncV3PlanningOrderCoverageFeedEntry,
|
|
25
26
|
}),
|
|
27
|
+
Object.freeze({
|
|
28
|
+
profile: WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_PROFILE,
|
|
29
|
+
policy: WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_POLICY,
|
|
30
|
+
validateEntry: validateWorkspaceSyncV3TaskCoverCoverageFeedEntry,
|
|
31
|
+
}),
|
|
26
32
|
]);
|
|
27
33
|
export function resolveWorkspaceSyncV3RegisteredCoverage(input) {
|
|
28
34
|
const profileId = String(input.coverageProfileId || '').trim();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type WorkspaceSyncV3ProjectionDescriptor = 'initiative/full-v1' | 'workstream/full-v1' | 'task/root-v1' | 'task-comments/full-v1' | 'task-checklist/full-v1' | 'task-attachment-links/full-v1' | 'entity-event/full-v1' | 'task-relationship/full-v1' | 'taxonomy/full-v1' | 'workflow-published-definition/full-v2' | 'workflow-execution/root-v1' | 'workflow-execution-event/full-v1' | 'workstream-task-order/full-v1';
|
|
1
|
+
export type WorkspaceSyncV3ProjectionDescriptor = 'initiative/full-v1' | 'workstream/full-v1' | 'task/root-v1' | 'task-comments/full-v1' | 'task-checklist/full-v1' | 'task-attachment-links/full-v1' | 'task-attachment-links/full-v2' | 'entity-event/full-v1' | 'task-relationship/full-v1' | 'taxonomy/full-v1' | 'workflow-published-definition/full-v2' | 'workflow-execution/root-v1' | 'workflow-execution-event/full-v1' | 'workstream-task-order/full-v1';
|
|
2
2
|
export type WorkspaceSyncV3JournalProjectionDescriptor = WorkspaceSyncV3ProjectionDescriptor | 'task/taxonomy-remap-v1';
|
|
3
3
|
export interface WorkspaceSyncV3ProjectionCoverageDescriptor {
|
|
4
4
|
projectionId: WorkspaceSyncV3ProjectionDescriptor;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isWorkspaceSyncV3CombinedLegacyFenceEnabled, normalizeWorkspaceSyncV2ProjectionExclusions, WORKSPACE_SYNC_V3_COMBINED_V2_EXCLUSIONS, } from './workspaceSyncV2ProjectionExclusions.js';
|
|
2
|
-
import { resolveWorkspaceSyncV3CombinedWireContract, } from './workspaceSyncV3CombinedWireContract.js';
|
|
1
|
+
import { isWorkspaceSyncV3CombinedLegacyFenceConfigured, isWorkspaceSyncV3CombinedLegacyFenceEnabled, normalizeWorkspaceSyncV2ProjectionExclusions, WORKSPACE_SYNC_V3_COMBINED_V2_EXCLUSIONS, } from './workspaceSyncV2ProjectionExclusions.js';
|
|
2
|
+
import { WORKSPACE_SYNC_V3_COMBINED_COVERAGE_SELECTOR, resolveWorkspaceSyncV3CombinedWireContract, } from './workspaceSyncV3CombinedWireContract.js';
|
|
3
3
|
import { resolveCombinedFeedCapability, resolveRequestedCombinedFeedCoverage } from './combinedFeedCapability.js';
|
|
4
4
|
export function isWorkspaceSyncV3NestedLegacyFenceEnabled(env = process.env) {
|
|
5
5
|
return /^(1|true|on|yes)$/i.test(String(env.TASKFORCE_SYNC_V3_NESTED_LEGACY_FENCE_ENABLED || '').trim());
|
|
@@ -17,17 +17,30 @@ export function resolveWorkspaceSyncV3RequiredCloudCoverage(env = process.env) {
|
|
|
17
17
|
export const resolveWorkspaceSyncV3RequiredPushCoverage = resolveWorkspaceSyncV3RequiredCloudCoverage;
|
|
18
18
|
export function resolveWorkspaceSyncV3AttestedV2Exclusions(input) {
|
|
19
19
|
const env = input.env || process.env;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
const runtimeMode = input.runtimeMode || 'cloud';
|
|
21
|
+
const localFenceEnabled = (coverage) => (isWorkspaceSyncV3CombinedLegacyFenceConfigured(env)
|
|
22
|
+
&& resolveCombinedFeedCapability({ runtimeMode: 'local', env, coverage })
|
|
23
|
+
.combinedFeed.activationReady);
|
|
24
|
+
if (input.coverage == null) {
|
|
25
|
+
const fenceEnabled = runtimeMode === 'local'
|
|
26
|
+
? localFenceEnabled(WORKSPACE_SYNC_V3_COMBINED_COVERAGE_SELECTOR)
|
|
27
|
+
: isWorkspaceSyncV3CombinedLegacyFenceEnabled(env);
|
|
28
|
+
return fenceEnabled ? WORKSPACE_SYNC_V3_COMBINED_V2_EXCLUSIONS : [];
|
|
29
|
+
}
|
|
24
30
|
if (!input.coverage || typeof input.coverage !== 'object' || Array.isArray(input.coverage))
|
|
25
31
|
return null;
|
|
26
32
|
const contract = resolveWorkspaceSyncV3CombinedWireContract(input.coverage);
|
|
27
|
-
if (!contract
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
if (!contract)
|
|
34
|
+
return null;
|
|
35
|
+
const fenceEnabled = runtimeMode === 'local'
|
|
36
|
+
? localFenceEnabled(contract.coverage)
|
|
37
|
+
: isWorkspaceSyncV3CombinedLegacyFenceEnabled(env)
|
|
38
|
+
&& (!contract.nestedWriterPrerequisitesRequired
|
|
39
|
+
|| (isWorkspaceSyncV3NestedLegacyFenceEnabled(env)
|
|
40
|
+
&& resolveCombinedFeedCapability({
|
|
41
|
+
runtimeMode: 'cloud', env, coverage: contract.coverage,
|
|
42
|
+
}).combinedFeed.activationReady));
|
|
43
|
+
if (!fenceEnabled)
|
|
31
44
|
return null;
|
|
32
45
|
if (!Array.isArray(input.excludedProjections))
|
|
33
46
|
return null;
|
|
@@ -23,6 +23,7 @@ export interface WorkspaceSyncV3NestedTaskApplyCore {
|
|
|
23
23
|
resolveTaskAttachmentLinksForDurableSync(links: ReturnType<typeof serializeWorkspaceSyncV3TaskAttachmentLinksPayload>['links'], workspaceId: string, options?: {
|
|
24
24
|
adoptAuthoritativeReferenceNumber?: boolean;
|
|
25
25
|
ignoreAssetMetadataSnapshots?: boolean;
|
|
26
|
+
restoreDeletedExternalAssetForAuthoritativeSync?: boolean;
|
|
26
27
|
}): AttachmentItem[];
|
|
27
28
|
listTaskAttachmentLinksForDurableSync(taskId: string, workspaceId: string): ReturnType<typeof serializeWorkspaceSyncV3TaskAttachmentLinksPayload>['links'];
|
|
28
29
|
getEntityEventForSync(input: {
|
|
@@ -71,12 +72,14 @@ export declare function resolveWorkspaceSyncV3AttachmentApplyObligations(input:
|
|
|
71
72
|
} | {
|
|
72
73
|
success: false;
|
|
73
74
|
error: string;
|
|
75
|
+
disposition?: 'retryable' | 'terminal-unavailable';
|
|
74
76
|
}>;
|
|
75
77
|
onInstalled?: (taskId: string) => void;
|
|
76
78
|
}): Promise<{
|
|
77
79
|
attempted: number;
|
|
78
80
|
resolved: number;
|
|
79
81
|
remaining: number;
|
|
82
|
+
terminal: number;
|
|
80
83
|
nextAttemptAt: string | null;
|
|
81
84
|
resolvedTaskIds: string[];
|
|
82
85
|
lastError: string | null;
|
|
@@ -2,7 +2,7 @@ import { DurableTaskAttachmentLinksApplyError } from '../../core/TaskAttachmentL
|
|
|
2
2
|
import { canonicalWorkspaceSyncJson } from './canonicalWorkspaceSyncJson.js';
|
|
3
3
|
import { fingerprintWorkspaceSyncPayload, hasCompletedRecoveryForSupersededEntityEvent, WorkspaceSyncDurabilityStore, } from './syncDurabilityStore.js';
|
|
4
4
|
import { calculateAttachmentApplyObligationRetryDelayMs, WorkspaceSyncV3AttachmentApplyObligationStore, } from './workspaceSyncV3AttachmentApplyObligationStore.js';
|
|
5
|
-
import { serializeWorkspaceSyncV3TaskAttachmentLinksPayload, serializeWorkspaceSyncV3TaskChecklistPayload, serializeWorkspaceSyncV3TaskCommentsPayload, serializeWorkspaceSyncV3EntityEventPayload, validateWorkspaceSyncV3EntityEventPayload, validateWorkspaceSyncV3TaskAttachmentLinksPayload, validateWorkspaceSyncV3TaskChecklistPayload, validateWorkspaceSyncV3TaskCommentAppendPayload, validateWorkspaceSyncV3TaskCommentsPayload, } from './workspaceSyncV3NestedTaskCodecs.js';
|
|
5
|
+
import { serializeWorkspaceSyncV3TaskAttachmentLinksPayload, serializeWorkspaceSyncV3TaskAttachmentLinksV2Payload, serializeWorkspaceSyncV3TaskChecklistPayload, serializeWorkspaceSyncV3TaskCommentsPayload, serializeWorkspaceSyncV3EntityEventPayload, validateWorkspaceSyncV3EntityEventPayload, validateWorkspaceSyncV3TaskAttachmentLinksPayload, validateWorkspaceSyncV3TaskAttachmentLinksV2Payload, validateWorkspaceSyncV3TaskChecklistPayload, validateWorkspaceSyncV3TaskCommentAppendPayload, validateWorkspaceSyncV3TaskCommentsPayload, } from './workspaceSyncV3NestedTaskCodecs.js';
|
|
6
6
|
import { validateWorkspaceSyncV3NestedTaskFeedEntry } from './workspaceSyncV3NestedTaskProjection.js';
|
|
7
7
|
export class WorkspaceSyncV3TaskCommentAggregateDivergenceError extends Error {
|
|
8
8
|
taskId;
|
|
@@ -50,6 +50,7 @@ function serializeTaskAttachmentLinkOwnership(payload) {
|
|
|
50
50
|
order: link.order,
|
|
51
51
|
...(link.displayName !== undefined ? { displayName: link.displayName } : {}),
|
|
52
52
|
})),
|
|
53
|
+
...('cardCoverAssetId' in payload ? { cardCoverAssetId: payload.cardCoverAssetId } : {}),
|
|
53
54
|
};
|
|
54
55
|
}
|
|
55
56
|
function applyEntry(core, workspaceId, entry, now, authoritativeEntityEventRecoveryIds) {
|
|
@@ -85,16 +86,22 @@ function applyEntry(core, workspaceId, entry, now, authoritativeEntityEventRecov
|
|
|
85
86
|
assertInstalledFingerprint(serializeWorkspaceSyncV3TaskChecklistPayload({ taskId: task.id, items: installed.checklistItems || [] }), entry.canonicalFingerprint || '', 'Task checklist');
|
|
86
87
|
return;
|
|
87
88
|
}
|
|
88
|
-
if (entry.projection === 'task-attachment-links/full-v1'
|
|
89
|
-
|
|
89
|
+
if (entry.projection === 'task-attachment-links/full-v1'
|
|
90
|
+
|| entry.projection === 'task-attachment-links/full-v2') {
|
|
91
|
+
const v2Payload = entry.projection === 'task-attachment-links/full-v2'
|
|
92
|
+
? validateWorkspaceSyncV3TaskAttachmentLinksV2Payload(entry.payload)
|
|
93
|
+
: null;
|
|
94
|
+
const payload = v2Payload ?? validateWorkspaceSyncV3TaskAttachmentLinksPayload(entry.payload);
|
|
95
|
+
const cardCoverAssetId = v2Payload?.cardCoverAssetId;
|
|
90
96
|
const task = taskOrThrow(core, payload.taskId, workspaceId);
|
|
91
97
|
const ownershipFingerprint = fingerprintWorkspaceSyncPayload(serializeTaskAttachmentLinkOwnership(payload));
|
|
92
98
|
const obligations = new WorkspaceSyncV3AttachmentApplyObligationStore(core.getDatabaseAdapter());
|
|
93
99
|
let attachments;
|
|
94
100
|
try {
|
|
95
|
-
attachments = core.resolveTaskAttachmentLinksForDurableSync(payload.links, workspaceId, {
|
|
101
|
+
attachments = core.getDatabaseAdapter().transaction(() => (core.resolveTaskAttachmentLinksForDurableSync(payload.links, workspaceId, {
|
|
96
102
|
ignoreAssetMetadataSnapshots: true,
|
|
97
|
-
|
|
103
|
+
restoreDeletedExternalAssetForAuthoritativeSync: true,
|
|
104
|
+
})))();
|
|
98
105
|
}
|
|
99
106
|
catch (error) {
|
|
100
107
|
if (error instanceof DurableTaskAttachmentLinksApplyError
|
|
@@ -122,10 +129,19 @@ function applyEntry(core, workspaceId, entry, now, authoritativeEntityEventRecov
|
|
|
122
129
|
}
|
|
123
130
|
throw error;
|
|
124
131
|
}
|
|
125
|
-
installTaskNestedFields(core, workspaceId, task, {
|
|
126
|
-
|
|
127
|
-
|
|
132
|
+
const installed = installTaskNestedFields(core, workspaceId, task, {
|
|
133
|
+
attachments,
|
|
134
|
+
...(cardCoverAssetId !== undefined ? { cardCoverAssetId } : {}),
|
|
128
135
|
});
|
|
136
|
+
const installedPayload = cardCoverAssetId !== undefined
|
|
137
|
+
? serializeWorkspaceSyncV3TaskAttachmentLinksV2Payload({
|
|
138
|
+
taskId: task.id,
|
|
139
|
+
links: core.listTaskAttachmentLinksForDurableSync(task.id, workspaceId),
|
|
140
|
+
cardCoverAssetId: installed.cardCoverAssetId ?? null,
|
|
141
|
+
})
|
|
142
|
+
: serializeWorkspaceSyncV3TaskAttachmentLinksPayload({
|
|
143
|
+
taskId: task.id, links: core.listTaskAttachmentLinksForDurableSync(task.id, workspaceId),
|
|
144
|
+
});
|
|
129
145
|
// Captions, original filenames, and readable references are snapshots of
|
|
130
146
|
// asset-owned metadata. A historical link event must remain installable
|
|
131
147
|
// after the asset is renamed or receives a new readable reference.
|
|
@@ -210,7 +226,14 @@ export async function resolveWorkspaceSyncV3AttachmentApplyObligations(input) {
|
|
|
210
226
|
let lastError = null;
|
|
211
227
|
for (const obligation of due) {
|
|
212
228
|
try {
|
|
213
|
-
const
|
|
229
|
+
const rawPayload = JSON.parse(obligation.payloadJson);
|
|
230
|
+
const hasCardCover = Object.prototype.hasOwnProperty.call(rawPayload, 'cardCoverAssetId');
|
|
231
|
+
const payload = hasCardCover
|
|
232
|
+
? validateWorkspaceSyncV3TaskAttachmentLinksV2Payload(rawPayload)
|
|
233
|
+
: validateWorkspaceSyncV3TaskAttachmentLinksPayload(rawPayload);
|
|
234
|
+
const cardCoverAssetId = hasCardCover
|
|
235
|
+
? payload.cardCoverAssetId
|
|
236
|
+
: undefined;
|
|
214
237
|
const installMutation = () => {
|
|
215
238
|
const task = input.core.getTask(payload.taskId, input.workspaceId);
|
|
216
239
|
if (!task) {
|
|
@@ -222,11 +245,22 @@ export async function resolveWorkspaceSyncV3AttachmentApplyObligations(input) {
|
|
|
222
245
|
}
|
|
223
246
|
const attachments = input.core.resolveTaskAttachmentLinksForDurableSync(payload.links, input.workspaceId, {
|
|
224
247
|
ignoreAssetMetadataSnapshots: true,
|
|
248
|
+
restoreDeletedExternalAssetForAuthoritativeSync: true,
|
|
225
249
|
});
|
|
226
|
-
installTaskNestedFields(input.core, input.workspaceId, task, {
|
|
227
|
-
|
|
228
|
-
|
|
250
|
+
const installed = installTaskNestedFields(input.core, input.workspaceId, task, {
|
|
251
|
+
attachments,
|
|
252
|
+
...(cardCoverAssetId !== undefined ? { cardCoverAssetId } : {}),
|
|
229
253
|
});
|
|
254
|
+
const installedPayload = cardCoverAssetId !== undefined
|
|
255
|
+
? serializeWorkspaceSyncV3TaskAttachmentLinksV2Payload({
|
|
256
|
+
taskId: task.id,
|
|
257
|
+
links: input.core.listTaskAttachmentLinksForDurableSync(task.id, input.workspaceId),
|
|
258
|
+
cardCoverAssetId: installed.cardCoverAssetId ?? null,
|
|
259
|
+
})
|
|
260
|
+
: serializeWorkspaceSyncV3TaskAttachmentLinksPayload({
|
|
261
|
+
taskId: task.id,
|
|
262
|
+
links: input.core.listTaskAttachmentLinksForDurableSync(task.id, input.workspaceId),
|
|
263
|
+
});
|
|
230
264
|
assertInstalledFingerprint(serializeTaskAttachmentLinkOwnership(installedPayload), fingerprintWorkspaceSyncPayload(serializeTaskAttachmentLinkOwnership(payload)), `Task attachment links for ${task.id}`);
|
|
231
265
|
obligationStore.resolve({
|
|
232
266
|
tenantId, workspaceId: input.workspaceId, taskId: obligation.taskId,
|
|
@@ -292,8 +326,20 @@ export async function resolveWorkspaceSyncV3AttachmentApplyObligations(input) {
|
|
|
292
326
|
if (!input.hydrateAsset || !assetId || hydratedAssetIds.has(assetId))
|
|
293
327
|
throw error;
|
|
294
328
|
const hydration = await input.hydrateAsset(assetId);
|
|
295
|
-
if (!hydration.success)
|
|
329
|
+
if (!hydration.success) {
|
|
330
|
+
if (hydration.disposition === 'terminal-unavailable') {
|
|
331
|
+
obligationStore.markTerminalUnavailable({
|
|
332
|
+
tenantId,
|
|
333
|
+
workspaceId: input.workspaceId,
|
|
334
|
+
taskId: obligation.taskId,
|
|
335
|
+
canonicalFingerprint: obligation.canonicalFingerprint,
|
|
336
|
+
reason: hydration.error,
|
|
337
|
+
now: input.now,
|
|
338
|
+
});
|
|
339
|
+
throw new TerminalAttachmentApplyObligationError(hydration.error);
|
|
340
|
+
}
|
|
296
341
|
throw new Error(hydration.error);
|
|
342
|
+
}
|
|
297
343
|
hydratedAssetIds.add(assetId);
|
|
298
344
|
}
|
|
299
345
|
}
|
|
@@ -304,6 +350,8 @@ export async function resolveWorkspaceSyncV3AttachmentApplyObligations(input) {
|
|
|
304
350
|
}
|
|
305
351
|
catch (error) {
|
|
306
352
|
lastError = error instanceof Error ? error.message : 'Deferred attachment-link retry failed.';
|
|
353
|
+
if (error instanceof TerminalAttachmentApplyObligationError)
|
|
354
|
+
continue;
|
|
307
355
|
const nextAttemptAt = new Date(Date.parse(input.now) + calculateAttachmentApplyObligationRetryDelayMs(obligation.attempts + 1)).toISOString();
|
|
308
356
|
obligationStore.recordAttemptFailure({
|
|
309
357
|
tenantId, workspaceId: input.workspaceId, taskId: obligation.taskId,
|
|
@@ -318,8 +366,11 @@ export async function resolveWorkspaceSyncV3AttachmentApplyObligations(input) {
|
|
|
318
366
|
attempted: due.length,
|
|
319
367
|
resolved,
|
|
320
368
|
remaining: summary.open,
|
|
369
|
+
terminal: summary.terminal,
|
|
321
370
|
nextAttemptAt: summary.nextAttemptAt,
|
|
322
371
|
resolvedTaskIds,
|
|
323
372
|
lastError: summary.lastError || lastError,
|
|
324
373
|
};
|
|
325
374
|
}
|
|
375
|
+
class TerminalAttachmentApplyObligationError extends Error {
|
|
376
|
+
}
|
|
@@ -18,6 +18,9 @@ export type WorkspaceSyncV3TaskAttachmentLinksPayload = {
|
|
|
18
18
|
taskId: string;
|
|
19
19
|
links: WorkspaceSyncV3TaskAttachmentLink[];
|
|
20
20
|
};
|
|
21
|
+
export type WorkspaceSyncV3TaskAttachmentLinksV2Payload = WorkspaceSyncV3TaskAttachmentLinksPayload & {
|
|
22
|
+
cardCoverAssetId: string | null;
|
|
23
|
+
};
|
|
21
24
|
export type WorkspaceSyncV3TaskAttachmentLink = {
|
|
22
25
|
assetId: string;
|
|
23
26
|
role: 'attachment' | 'image' | 'reference';
|
|
@@ -55,5 +58,11 @@ export declare function serializeWorkspaceSyncV3TaskAttachmentLinksPayload(input
|
|
|
55
58
|
links: unknown;
|
|
56
59
|
}): WorkspaceSyncV3TaskAttachmentLinksPayload;
|
|
57
60
|
export declare function validateWorkspaceSyncV3TaskAttachmentLinksPayload(value: unknown): WorkspaceSyncV3TaskAttachmentLinksPayload;
|
|
61
|
+
export declare function serializeWorkspaceSyncV3TaskAttachmentLinksV2Payload(input: {
|
|
62
|
+
taskId: string;
|
|
63
|
+
links: unknown;
|
|
64
|
+
cardCoverAssetId: unknown;
|
|
65
|
+
}): WorkspaceSyncV3TaskAttachmentLinksV2Payload;
|
|
66
|
+
export declare function validateWorkspaceSyncV3TaskAttachmentLinksV2Payload(value: unknown): WorkspaceSyncV3TaskAttachmentLinksV2Payload;
|
|
58
67
|
export declare function serializeWorkspaceSyncV3EntityEventPayload(event: EntityEvent): WorkspaceSyncEntityEventSnapshot;
|
|
59
68
|
export declare function validateWorkspaceSyncV3EntityEventPayload(value: unknown): WorkspaceSyncEntityEventSnapshot;
|
|
@@ -279,6 +279,32 @@ export function validateWorkspaceSyncV3TaskAttachmentLinksPayload(value) {
|
|
|
279
279
|
}
|
|
280
280
|
return canonical;
|
|
281
281
|
}
|
|
282
|
+
export function serializeWorkspaceSyncV3TaskAttachmentLinksV2Payload(input) {
|
|
283
|
+
const canonical = serializeWorkspaceSyncV3TaskAttachmentLinksPayload(input);
|
|
284
|
+
const cardCoverAssetId = input.cardCoverAssetId == null
|
|
285
|
+
? null
|
|
286
|
+
: requiredId(input.cardCoverAssetId, 'Task attachment links cardCoverAssetId');
|
|
287
|
+
if (cardCoverAssetId !== null && !canonical.links.some((link) => (link.assetId === cardCoverAssetId && link.role === 'image'))) {
|
|
288
|
+
throw new Error('Task attachment links cardCoverAssetId must reference an image link.');
|
|
289
|
+
}
|
|
290
|
+
return { ...canonical, cardCoverAssetId };
|
|
291
|
+
}
|
|
292
|
+
export function validateWorkspaceSyncV3TaskAttachmentLinksV2Payload(value) {
|
|
293
|
+
const source = record(value, 'Task attachment links v2 payload');
|
|
294
|
+
exactKeys(source, new Set(['taskId', 'links', 'cardCoverAssetId']), 'Task attachment links v2 payload');
|
|
295
|
+
if (!Object.prototype.hasOwnProperty.call(source, 'cardCoverAssetId')) {
|
|
296
|
+
throw new Error('Task attachment links v2 payload must explicitly carry cardCoverAssetId.');
|
|
297
|
+
}
|
|
298
|
+
const canonical = serializeWorkspaceSyncV3TaskAttachmentLinksV2Payload({
|
|
299
|
+
taskId: requiredId(source.taskId, 'Task attachment links taskId'),
|
|
300
|
+
links: source.links,
|
|
301
|
+
cardCoverAssetId: source.cardCoverAssetId,
|
|
302
|
+
});
|
|
303
|
+
if (canonicalWorkspaceSyncJson(canonical) !== canonicalWorkspaceSyncJson(value)) {
|
|
304
|
+
throw new Error('Task attachment links v2 payload is not canonically ordered or normalized.');
|
|
305
|
+
}
|
|
306
|
+
return canonical;
|
|
307
|
+
}
|
|
282
308
|
export function serializeWorkspaceSyncV3EntityEventPayload(event) {
|
|
283
309
|
const serialized = serializeEntityActivityForSync(event);
|
|
284
310
|
assertMetadataOnly(serialized.details, 'Entity event details');
|
|
@@ -33,15 +33,25 @@ export declare const WORKSPACE_SYNC_V3_NESTED_TASK_PROJECTIONS: readonly [Readon
|
|
|
33
33
|
dependencies: readonly ["initiative/full-v1", "workstream/full-v1", "task/root-v1"];
|
|
34
34
|
operationAtomic: true;
|
|
35
35
|
}>];
|
|
36
|
+
export declare const WORKSPACE_SYNC_V3_TASK_ATTACHMENT_LINKS_V2_PROJECTION: Readonly<{
|
|
37
|
+
readonly projectionId: "task-attachment-links/full-v2";
|
|
38
|
+
readonly domain: "task-attachment-links";
|
|
39
|
+
readonly schemaVersion: 2;
|
|
40
|
+
readonly mutationKinds: readonly string[];
|
|
41
|
+
readonly fields: readonly string[];
|
|
42
|
+
readonly dependencies: readonly ["task/root-v1"];
|
|
43
|
+
readonly operationAtomic: true;
|
|
44
|
+
}>;
|
|
36
45
|
export declare function projectWorkspaceSyncV3NestedTaskJournalRow(row: WorkspaceSyncJournalRow): WorkspaceSyncV3FeedEntry | null;
|
|
46
|
+
export declare function projectWorkspaceSyncV3NestedTaskV2JournalRow(row: WorkspaceSyncJournalRow): WorkspaceSyncV3FeedEntry | null;
|
|
37
47
|
export declare function validateWorkspaceSyncV3NestedTaskFeedEntry(entry: WorkspaceSyncV3FeedEntry): void;
|
|
38
|
-
/**
|
|
39
|
-
* Operation projector for nested/event coverage. Ordinary writers emit
|
|
40
|
-
* parent-first operations; repair baselines and comment reconcile may emit
|
|
41
|
-
* nested-only groups that still project when every row is a nested domain.
|
|
42
|
-
*/
|
|
43
48
|
export declare function projectWorkspaceSyncV3NestedTaskOperation(input: {
|
|
44
49
|
rows: readonly WorkspaceSyncJournalRow[];
|
|
45
50
|
cycleHighWatermark: string;
|
|
46
51
|
followingRow?: WorkspaceSyncJournalRow | null;
|
|
47
52
|
}): WorkspaceSyncV3FeedEntry[] | null;
|
|
53
|
+
export declare function projectWorkspaceSyncV3NestedTaskV2Operation(input: {
|
|
54
|
+
rows: readonly WorkspaceSyncJournalRow[];
|
|
55
|
+
cycleHighWatermark: string;
|
|
56
|
+
followingRow?: WorkspaceSyncJournalRow | null;
|
|
57
|
+
}): WorkspaceSyncV3FeedEntry[] | null;
|