@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.
Files changed (264) hide show
  1. package/dist/Taskforce.module.css +233 -34
  2. package/dist/TaskforceCore.js +237 -230
  3. package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.js +1 -1
  4. package/dist/cli.js +34 -0
  5. package/dist/cliCloudTargetGuard.d.ts +5 -0
  6. package/dist/cliCloudTargetGuard.js +11 -0
  7. package/dist/components/features/AnnotatedAttachmentWorkspace.js +24 -8
  8. package/dist/components/features/TaskSettings.d.ts +12 -1
  9. package/dist/components/features/TaskSettings.js +147 -40
  10. package/dist/components/features/agentCapabilities/AgentCapabilitiesPrototype.d.ts +1 -1
  11. package/dist/components/features/planning/PlanningModule.js +2 -5
  12. package/dist/components/features/planning/PlanningTaskOrderList.d.ts +1 -1
  13. package/dist/components/features/planning/PlanningTaskOrderList.js +17 -6
  14. package/dist/components/features/planning/planningTaskArrangement.d.ts +1 -0
  15. package/dist/components/features/planning/planningTaskArrangement.js +5 -5
  16. package/dist/components/features/taskforceAgentEditorModel.js +3 -1
  17. package/dist/components/task/TaskCard.d.ts +5 -0
  18. package/dist/components/task/TaskCard.js +65 -10
  19. package/dist/components/task/TaskImageReviews.js +14 -5
  20. package/dist/components/task/TaskKanban.d.ts +6 -1
  21. package/dist/components/task/TaskKanban.js +152 -6
  22. package/dist/components/task/TaskList.d.ts +5 -0
  23. package/dist/components/task/TaskList.js +3 -3
  24. package/dist/components/ui/PasswordInput.d.ts +6 -0
  25. package/dist/components/ui/PasswordInput.js +11 -0
  26. package/dist/components/ui/TopNoticeLayer.js +1 -1
  27. package/dist/components/views/AppShellHeader.js +32 -11
  28. package/dist/components/views/PlanComparisonPage.js +12 -0
  29. package/dist/components/views/StandaloneLayout.js +7 -31
  30. package/dist/components/views/WidgetView.js +3 -3
  31. package/dist/components/views/panels/PlanningDrawer.js +5 -12
  32. package/dist/components/views/standalone/modals/AccountSettingsModal.js +26 -17
  33. package/dist/config/envSchema.js +12 -0
  34. package/dist/config/localServiceRuntimeContract.d.ts +13 -0
  35. package/dist/config/localServiceRuntimeContract.js +135 -0
  36. package/dist/core/AiProfileService.js +46 -8
  37. package/dist/core/DeletedTaskLifecycleService.d.ts +1 -0
  38. package/dist/core/DeletedTaskLifecycleService.js +37 -6
  39. package/dist/core/TaskAttachmentLinksDurableMutationService.d.ts +3 -2
  40. package/dist/core/TaskAttachmentLinksDurableMutationService.js +33 -9
  41. package/dist/core/Taskforce.d.ts +62 -2
  42. package/dist/core/Taskforce.js +635 -32
  43. package/dist/core/types.d.ts +6 -0
  44. package/dist/hooks/sync/useDurableLocalOutboxDrain.d.ts +1 -1
  45. package/dist/hooks/sync/useDurableTaskCreateMutation.js +1 -1
  46. package/dist/hooks/sync/useDurableTaskMetadataMutation.d.ts +1 -0
  47. package/dist/hooks/sync/useDurableTaskMetadataMutation.js +1 -0
  48. package/dist/hooks/sync/useDurableTaskStatusMutation.d.ts +1 -0
  49. package/dist/hooks/tasks/taskHttpMutation.js +1 -0
  50. package/dist/hooks/tasks/useCloudTaskSearch.d.ts +12 -0
  51. package/dist/hooks/tasks/useCloudTaskSearch.js +71 -0
  52. package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.d.ts +16 -0
  53. package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.js +197 -0
  54. package/dist/hooks/tasks/useTaskEditorNavigation.d.ts +16 -3
  55. package/dist/hooks/tasks/useTaskEditorNavigation.js +72 -13
  56. package/dist/hooks/tasks/useTaskFormActions.d.ts +6 -0
  57. package/dist/hooks/tasks/useTaskFormActions.js +65 -12
  58. package/dist/hooks/ui/useSettingsModel.d.ts +24 -2
  59. package/dist/hooks/ui/useSettingsModel.js +13 -2
  60. package/dist/hooks/ui/useSettingsPersistence.d.ts +12 -1
  61. package/dist/hooks/ui/useSettingsPersistence.js +74 -47
  62. package/dist/hooks/useFilterSort.d.ts +7 -3
  63. package/dist/hooks/useFilterSort.js +15 -5
  64. package/dist/hooks/useTaskData.d.ts +10 -1
  65. package/dist/hooks/useTaskData.js +216 -7
  66. package/dist/hooks/useTaskMutations.d.ts +10 -2
  67. package/dist/hooks/useTaskMutations.js +223 -43
  68. package/dist/hooks/useTaskforce.d.ts +37 -9
  69. package/dist/hooks/useTaskforce.js +349 -39
  70. package/dist/hooks/useUiNotice.d.ts +4 -0
  71. package/dist/hooks/useUiNotice.js +4 -0
  72. package/dist/mcp/adminWorkspaceRegistrar.js +3 -3
  73. package/dist/mcp/documentAssetRegistrar.js +44 -35
  74. package/dist/mcp/documentHelpers.d.ts +1 -0
  75. package/dist/mcp/documentHelpers.js +7 -3
  76. package/dist/mcp/runtime.js +172 -42
  77. package/dist/mcp/taskPlanningRegistrar.js +41 -38
  78. package/dist/mcp/toolCallCompatibility.js +38 -1
  79. package/dist/mcp/toolCatalog.d.ts +1 -0
  80. package/dist/migrations/taskSchemaMigrations.js +12 -0
  81. package/dist/runtime/appGateDefinitions.d.ts +30 -6
  82. package/dist/runtime/appGateDefinitions.js +6 -6
  83. package/dist/runtime/appGates.d.ts +12 -13
  84. package/dist/runtime/appGates.js +29 -13
  85. package/dist/runtime/nodeAppGates.d.ts +8 -0
  86. package/dist/runtime/nodeAppGates.js +27 -0
  87. package/dist/server/cloudCollectionRead.d.ts +1 -1
  88. package/dist/server/cloudCollectionRead.js +2 -2
  89. package/dist/server/index.d.ts +3 -0
  90. package/dist/server/index.js +15 -3
  91. package/dist/server/localServiceLease.d.ts +3 -0
  92. package/dist/server/localServiceLease.js +9 -1
  93. package/dist/server/localWorkspaceSyncServerRuntime.js +10 -3
  94. package/dist/server/rateLimit.d.ts +1 -0
  95. package/dist/server/rateLimit.js +4 -0
  96. package/dist/server/realtimeSyncWs.js +36 -12
  97. package/dist/server/routes/admin.js +1 -0
  98. package/dist/server/routes/agentRoles.js +3 -2
  99. package/dist/server/routes/agentSkills.js +3 -2
  100. package/dist/server/routes/agents.js +118 -16
  101. package/dist/server/routes/annotatedAttachments.js +3 -2
  102. package/dist/server/routes/auth.js +3 -1
  103. package/dist/server/routes/durableTaskHttpRouters.d.ts +9 -2
  104. package/dist/server/routes/localService.js +2 -0
  105. package/dist/server/routes/primitives.d.ts +2 -0
  106. package/dist/server/routes/syncAuxRoutes.js +5 -2
  107. package/dist/server/routes/syncPullApplyRoutes.js +23 -4
  108. package/dist/server/routes/syncV3FeedRoutes.js +18 -16
  109. package/dist/server/routes/syncV3LocalCaptureRoutes.js +28 -2
  110. package/dist/server/routes/syncV3LocalFeedApplyRoutes.d.ts +1 -0
  111. package/dist/server/routes/syncV3LocalFeedApplyRoutes.js +26 -0
  112. package/dist/server/routes/syncV3OperationRoutes.js +10 -0
  113. package/dist/server/routes/tasks.js +103 -11
  114. package/dist/server/routes/workspaces.js +43 -1
  115. package/dist/server/workspaceDeletionAdmission.d.ts +23 -0
  116. package/dist/server/workspaceDeletionAdmission.js +50 -0
  117. package/dist/service/localServiceCli.js +16 -0
  118. package/dist/service/localServiceClientLifecycle.js +36 -10
  119. package/dist/services/codexAppServerModelGateway.d.ts +112 -0
  120. package/dist/services/codexAppServerModelGateway.js +438 -0
  121. package/dist/services/taskforceAgentMcpBridge.d.ts +7 -1
  122. package/dist/services/taskforceAgentMcpBridge.js +23 -3
  123. package/dist/shared/taskforceAgentDefinition.js +7 -1
  124. package/dist/shared/taskforceAgentModels.d.ts +1 -0
  125. package/dist/shared/taskforceAgentModels.js +30 -1
  126. package/dist/storage/postgresAdapter.d.ts +20 -3
  127. package/dist/storage/postgresAdapter.js +106 -14
  128. package/dist/storage/postgresWorker.js +13 -4
  129. package/dist/storage/postgresWorkerProtocol.d.ts +29 -0
  130. package/dist/storage/postgresWorkerProtocol.js +30 -0
  131. package/dist/sync/cloudSyncApi.d.ts +4 -1
  132. package/dist/sync/cloudSyncApi.js +7 -2
  133. package/dist/sync/contentSyncState.d.ts +1 -1
  134. package/dist/sync/coordinator/localSyncExecutionPermitStore.d.ts +1 -0
  135. package/dist/sync/coordinator/localSyncExecutionPermitStore.js +7 -1
  136. package/dist/sync/coordinator/localWorkspaceSyncRunner.js +6 -2
  137. package/dist/sync/engine/workspaceSyncEngineBrowserGatewayRemoteServices.js +20 -2
  138. package/dist/sync/engine/workspaceSyncEngineLocalServices.d.ts +4 -0
  139. package/dist/sync/engine/workspaceSyncEngineLocalServices.js +11 -0
  140. package/dist/sync/engine/workspaceSyncEngineRemoteServices.d.ts +11 -0
  141. package/dist/sync/engine/workspaceSyncEngineRemoteServices.js +2 -1
  142. package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.js +31 -4
  143. package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.d.ts +3 -1
  144. package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +25 -8
  145. package/dist/sync/engine/workspaceSyncEngineTransfers.d.ts +1 -1
  146. package/dist/sync/engine/workspaceSyncEngineTransfers.js +8 -3
  147. package/dist/sync/syncService.d.ts +2 -0
  148. package/dist/sync/syncService.js +4 -1
  149. package/dist/sync/v3/combinedFeedCapability.js +4 -0
  150. package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.d.ts +2 -0
  151. package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.js +11 -1
  152. package/dist/sync/v3/durableTaskChecklistMutationRouter.d.ts +2 -0
  153. package/dist/sync/v3/durableTaskChecklistMutationRouter.js +4 -0
  154. package/dist/sync/v3/durableTaskHttpBulkMutationRouter.d.ts +1 -0
  155. package/dist/sync/v3/durableTaskHttpBulkMutationRouter.js +30 -8
  156. package/dist/sync/v3/durableTaskHttpRootMutationRouter.d.ts +5 -3
  157. package/dist/sync/v3/durableTaskHttpRootMutationRouter.js +27 -2
  158. package/dist/sync/v3/localTaskAttachmentLinksOutboxService.d.ts +2 -0
  159. package/dist/sync/v3/localTaskAttachmentLinksOutboxService.js +47 -7
  160. package/dist/sync/v3/localTaskCreateOutboxService.js +15 -6
  161. package/dist/sync/v3/localTaskMetadataClient.d.ts +1 -0
  162. package/dist/sync/v3/localTaskMetadataClient.js +1 -0
  163. package/dist/sync/v3/localTaskMetadataOutboxHandler.js +5 -1
  164. package/dist/sync/v3/localTaskMetadataOutboxService.d.ts +2 -0
  165. package/dist/sync/v3/localTaskMetadataOutboxService.js +7 -0
  166. package/dist/sync/v3/localTaskRestoreOutboxService.js +14 -6
  167. package/dist/sync/v3/localTaskStatusClient.d.ts +1 -0
  168. package/dist/sync/v3/localTaskStatusClient.js +6 -1
  169. package/dist/sync/v3/localTaskStatusOutboxService.d.ts +2 -0
  170. package/dist/sync/v3/localTaskStatusOutboxService.js +54 -13
  171. package/dist/sync/v3/syncDurabilityStore.d.ts +7 -0
  172. package/dist/sync/v3/syncDurabilityStore.js +31 -11
  173. package/dist/sync/v3/taskAttachmentLinksMutationService.d.ts +6 -4
  174. package/dist/sync/v3/taskAttachmentLinksMutationService.js +19 -10
  175. package/dist/sync/v3/taskChecklistMutationService.d.ts +4 -2
  176. package/dist/sync/v3/taskChecklistMutationService.js +4 -0
  177. package/dist/sync/v3/taskCreateMutationService.d.ts +2 -2
  178. package/dist/sync/v3/taskCreateMutationService.js +7 -4
  179. package/dist/sync/v3/taskMetadataMutationService.d.ts +3 -0
  180. package/dist/sync/v3/taskMetadataMutationService.js +4 -0
  181. package/dist/sync/v3/taskRestoreMutationService.d.ts +2 -2
  182. package/dist/sync/v3/taskRestoreMutationService.js +7 -4
  183. package/dist/sync/v3/taskStatusMutationService.d.ts +2 -0
  184. package/dist/sync/v3/taskStatusMutationService.js +4 -0
  185. package/dist/sync/v3/workflowAssignmentSync.d.ts +1 -0
  186. package/dist/sync/v3/workflowAssignmentSync.js +3 -0
  187. package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.d.ts +1 -1
  188. package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.js +13 -3
  189. package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.d.ts +11 -0
  190. package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.js +27 -10
  191. package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.d.ts +2 -1
  192. package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.js +52 -10
  193. package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.js +9 -1
  194. package/dist/sync/v3/workspaceSyncV3CombinedFeedOrchestrator.js +8 -3
  195. package/dist/sync/v3/workspaceSyncV3CombinedLocalApply.js +51 -10
  196. package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.d.ts +7 -0
  197. package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.js +30 -18
  198. package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.d.ts +9 -4
  199. package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.js +98 -47
  200. package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.d.ts +10 -0
  201. package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.js +58 -21
  202. package/dist/sync/v3/workspaceSyncV3CombinedWireContract.d.ts +3 -1
  203. package/dist/sync/v3/workspaceSyncV3CombinedWireContract.js +18 -0
  204. package/dist/sync/v3/workspaceSyncV3CoverageRegistry.js +6 -0
  205. package/dist/sync/v3/workspaceSyncV3FeedProfile.d.ts +1 -1
  206. package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.d.ts +1 -0
  207. package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.js +23 -10
  208. package/dist/sync/v3/workspaceSyncV3NestedTaskApply.d.ts +3 -0
  209. package/dist/sync/v3/workspaceSyncV3NestedTaskApply.js +64 -13
  210. package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.d.ts +9 -0
  211. package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.js +26 -0
  212. package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.d.ts +15 -5
  213. package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.js +50 -14
  214. package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.d.ts +2 -1
  215. package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.js +11 -3
  216. package/dist/sync/v3/workspaceSyncV3OperationProtocol.d.ts +2 -0
  217. package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.d.ts +2 -0
  218. package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.js +19 -7
  219. package/dist/sync/v3/workspaceSyncV3TaskCommentAudit.js +9 -2
  220. package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.d.ts +7 -0
  221. package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.js +37 -0
  222. package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.d.ts +6 -0
  223. package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.js +9 -0
  224. package/dist/sync/workspacePullFeed.js +2 -1
  225. package/dist/sync/workspaceRepair.d.ts +3 -0
  226. package/dist/sync/workspaceRepair.js +67 -6
  227. package/dist/types.d.ts +47 -1
  228. package/dist/types.js +6 -0
  229. package/dist/ui/assets/{AiIdentityRosterCard-MZs7lVED.js → AiIdentityRosterCard-BZM4aQnM.js} +1 -1
  230. package/dist/ui/assets/AiProfilesModule-BbAEWtHH.js +1 -0
  231. package/dist/ui/assets/AnnotatedAttachmentWorkspace-B68Wg-RV.js +3 -0
  232. package/dist/ui/assets/AnnotatedAttachmentWorkspace-TzYu7pkG.css +1 -0
  233. package/dist/ui/assets/{AssetTraySortControl-Kf1pelSy.js → AssetTraySortControl-C8Rztyal.js} +1 -1
  234. package/dist/ui/assets/{ContextAttachmentManager-B8boOs6Q.js → ContextAttachmentManager-Cj3c7X9y.js} +2 -2
  235. package/dist/ui/assets/{DocumentWorkspace-DXH4XUsB.js → DocumentWorkspace-B5uvzems.js} +1 -1
  236. package/dist/ui/assets/{EntityActivityTimeline-BtSTq0ON.js → EntityActivityTimeline-BVFvCB5R.js} +1 -1
  237. package/dist/ui/assets/PlanningModule-B5DWQOGz.js +1 -0
  238. package/dist/ui/assets/PlansPage-AY4cGWco.js +1 -0
  239. package/dist/ui/assets/TaskContextUpload-DZxTVesW.js +1 -0
  240. package/dist/ui/assets/TaskSettings-BeWAuyZj.js +12 -0
  241. package/dist/ui/assets/{TaskforceAgentsModule-BazdUwxZ.js → TaskforceAgentsModule-BifCYtjR.js} +6 -6
  242. package/dist/ui/assets/{WorkflowManagerModule-DWFspC-o.js → WorkflowManagerModule-DEr5di_r.js} +1 -1
  243. package/dist/ui/assets/index-I5zhdtgt.js +7 -0
  244. package/dist/ui/assets/index-VRFsx3wz.css +1 -0
  245. package/dist/ui/assets/{vendor-icons-BkFLXavV.js → vendor-icons-D9Lpw-j4.js} +1 -1
  246. package/dist/ui/index.html +3 -3
  247. package/dist/utils/taskActivity.d.ts +3 -2
  248. package/dist/utils/taskActivity.js +19 -2
  249. package/dist/utils/taskEditorReconciliation.d.ts +40 -0
  250. package/dist/utils/taskEditorReconciliation.js +217 -0
  251. package/dist/utils/taskNormalization.d.ts +1 -0
  252. package/dist/utils/taskNormalization.js +39 -0
  253. package/dist/utils/taskSearch.js +2 -2
  254. package/dist/utils/uiNotice.d.ts +4 -0
  255. package/package.json +16 -4
  256. package/dist/ui/assets/AiProfilesModule-C3i0LOxe.js +0 -1
  257. package/dist/ui/assets/AnnotatedAttachmentWorkspace-CBRZ8rca.css +0 -1
  258. package/dist/ui/assets/AnnotatedAttachmentWorkspace-DVZk5Tln.js +0 -3
  259. package/dist/ui/assets/PlanningModule-BPVyEa-f.js +0 -1
  260. package/dist/ui/assets/PlansPage-ChqgxALc.js +0 -1
  261. package/dist/ui/assets/TaskContextUpload-CB3ol0sN.js +0 -1
  262. package/dist/ui/assets/TaskSettings-g4ECKNOz.js +0 -12
  263. package/dist/ui/assets/index-BUplSsv_.js +0 -7
  264. package/dist/ui/assets/index-gz2EXuoK.css +0 -1
@@ -6,7 +6,7 @@ import { validateWorkspaceSyncV3CombinedRepairPage, WorkspaceSyncV3CombinedProje
6
6
  import { fingerprintWorkspaceSyncPayload, WorkspaceSyncDurabilityStore } from './syncDurabilityStore.js';
7
7
  import { WorkflowStore } from '../../storage/workflowStore.js';
8
8
  import { serializeTaskRelationshipForSync } from './workspaceSyncV3TaskRelationshipProjection.js';
9
- import { serializeWorkspaceSyncV3EntityEventPayload, serializeWorkspaceSyncV3TaskAttachmentLinksPayload, serializeWorkspaceSyncV3TaskChecklistPayload, serializeWorkspaceSyncV3TaskCommentsPayload, validateWorkspaceSyncV3EntityEventPayload, } from './workspaceSyncV3NestedTaskCodecs.js';
9
+ import { serializeWorkspaceSyncV3EntityEventPayload, serializeWorkspaceSyncV3TaskAttachmentLinksPayload, serializeWorkspaceSyncV3TaskAttachmentLinksV2Payload, serializeWorkspaceSyncV3TaskChecklistPayload, serializeWorkspaceSyncV3TaskCommentsPayload, validateWorkspaceSyncV3EntityEventPayload, } from './workspaceSyncV3NestedTaskCodecs.js';
10
10
  import { applyWorkspaceSyncV3NestedTaskEntries, WorkspaceSyncV3TaskCommentAggregateDivergenceError, } from './workspaceSyncV3NestedTaskApply.js';
11
11
  import { LocalSyncIdentityStore } from './localSyncIdentityStore.js';
12
12
  import { enqueueLocalTaskCommentReconciliation } from './localTaskCommentOutboxService.js';
@@ -25,7 +25,8 @@ function combinedRepairBaselineMarker(page) {
25
25
  })}`;
26
26
  }
27
27
  const NESTED_TASK_PROJECTIONS = new Set([
28
- 'task-comments/full-v1', 'task-checklist/full-v1', 'task-attachment-links/full-v1', 'entity-event/full-v1',
28
+ 'task-comments/full-v1', 'task-checklist/full-v1', 'task-attachment-links/full-v1',
29
+ 'task-attachment-links/full-v2', 'entity-event/full-v1',
29
30
  ]);
30
31
  const WORKFLOW_RUNTIME_PROJECTIONS = new Set([
31
32
  'workflow-published-definition/full-v2',
@@ -59,7 +60,8 @@ function coveredDomains(projections) {
59
60
  domains.push('task-comments');
60
61
  if (projections.has('task-checklist/full-v1'))
61
62
  domains.push('task-checklist');
62
- if (projections.has('task-attachment-links/full-v1'))
63
+ if (projections.has('task-attachment-links/full-v1')
64
+ || projections.has('task-attachment-links/full-v2'))
63
65
  domains.push('task-attachment-links');
64
66
  if (projections.has('entity-event/full-v1'))
65
67
  domains.push('entity-event');
@@ -181,6 +183,15 @@ function isExactPlanningRootProjectionReplay(input) {
181
183
  && input.current.lastSequence === input.entry.sequence
182
184
  && input.current.canonicalFingerprint === (input.entry.canonicalFingerprint || input.entry.payloadFingerprint);
183
185
  }
186
+ function parentOwnedNestedTaskId(entry) {
187
+ if (entry.projection === 'task-comments/full-v1'
188
+ || entry.projection === 'task-checklist/full-v1'
189
+ || entry.projection === 'task-attachment-links/full-v1'
190
+ || entry.projection === 'task-attachment-links/full-v2') {
191
+ return entry.entityId;
192
+ }
193
+ return null;
194
+ }
184
195
  function applyEntries(input) {
185
196
  const store = new WorkspaceSyncDurabilityStore(input.core.getDatabaseAdapter());
186
197
  const workflowApply = prepareWorkspaceSyncV3WorkflowRuntimeApply({
@@ -200,9 +211,13 @@ function applyEntries(input) {
200
211
  throw coveredLocalOperationsError('Combined feed apply is blocked by covered local operations.');
201
212
  }
202
213
  const notices = notifications();
214
+ const deletedTaskRoots = new Set();
203
215
  for (const entry of input.entries) {
204
216
  let taskChange = null;
205
217
  let nestedTaskChangeId = null;
218
+ const nestedTaskId = parentOwnedNestedTaskId(entry);
219
+ if (nestedTaskId && deletedTaskRoots.has(nestedTaskId))
220
+ continue;
206
221
  const current = store.readWorkspaceDomainOwnership({ tenantId: input.tenantId,
207
222
  workspaceId: input.workspaceId, domain: entry.domain, entityId: entry.entityId });
208
223
  const exactTaskRootReplay = isExactTaskRootProjectionReplay({ entry, current });
@@ -288,6 +303,16 @@ function applyEntries(input) {
288
303
  shouldRecordRevision: (result) => result?.state !== 'deferred',
289
304
  });
290
305
  }
306
+ if (entry.projection === 'task/root-v1') {
307
+ if (taskChange === 'upsert') {
308
+ deletedTaskRoots.delete(entry.entityId);
309
+ }
310
+ else if (taskChange === 'delete'
311
+ || (!input.core.getTask(entry.entityId, input.workspaceId)
312
+ && input.core.hasTaskDeletionMarkerForSync(entry.entityId, input.workspaceId))) {
313
+ deletedTaskRoots.add(entry.entityId);
314
+ }
315
+ }
291
316
  if (applied.state !== 'applied')
292
317
  continue;
293
318
  if (entry.projection === 'task/root-v1' && entry.mutationKind !== 'delete') {
@@ -366,12 +391,19 @@ function listLocalTaskNestedProjection(core, workspaceId, projection) {
366
391
  taskId: task.id, items: task.checklistItems || [],
367
392
  }));
368
393
  }
369
- else {
394
+ else if (projection === 'task-attachment-links/full-v1') {
370
395
  values.set(task.id, serializeWorkspaceSyncV3TaskAttachmentLinksPayload({
371
396
  taskId: task.id,
372
397
  links: core.listTaskAttachmentLinksForDurableSync(task.id, workspaceId),
373
398
  }));
374
399
  }
400
+ else {
401
+ values.set(task.id, serializeWorkspaceSyncV3TaskAttachmentLinksV2Payload({
402
+ taskId: task.id,
403
+ links: core.listTaskAttachmentLinksForDurableSync(task.id, workspaceId),
404
+ cardCoverAssetId: task.cardCoverAssetId ?? null,
405
+ }));
406
+ }
375
407
  }
376
408
  const last = page.at(-1);
377
409
  cursor = page.length === 1000 && last
@@ -416,6 +448,9 @@ function nestedLocalDomains(core, workspaceId, projections, liveEntityIds) {
416
448
  if (projections.has('task-attachment-links/full-v1')) {
417
449
  domains.push(['task-attachment-links', listLocalTaskNestedProjection(core, workspaceId, 'task-attachment-links/full-v1')]);
418
450
  }
451
+ else if (projections.has('task-attachment-links/full-v2')) {
452
+ domains.push(['task-attachment-links', listLocalTaskNestedProjection(core, workspaceId, 'task-attachment-links/full-v2')]);
453
+ }
419
454
  if (projections.has('entity-event/full-v1')) {
420
455
  domains.push(['entity-event', listLocalEntityEvents(core, workspaceId, liveEntityIds)]);
421
456
  }
@@ -560,13 +595,18 @@ function isCompatibleLegacyAttachmentLinks(core, workspaceId, local, incoming) {
560
595
  if (!value || typeof value !== 'object' || Array.isArray(value))
561
596
  return false;
562
597
  const incomingLink = value;
563
- if (localLink.role !== incomingLink.role)
564
- return false;
565
598
  const localAsset = store.get(String(localLink.assetId || ''), workspaceId);
566
599
  const incomingAsset = store.get(String(incomingLink.assetId || ''), workspaceId);
567
600
  if (!localAsset || !incomingAsset || localAsset.deletedAt || incomingAsset.deletedAt
568
601
  || localAsset.storageKey !== incomingAsset.storageKey)
569
602
  return false;
603
+ const compatibleRole = localLink.role === incomingLink.role
604
+ || (localAsset.storageProvider === 'external'
605
+ && localLink.role === 'reference'
606
+ && incomingAsset.storageProvider !== 'external'
607
+ && incomingLink.role === (incomingAsset.kind === 'image' ? 'image' : 'attachment'));
608
+ if (!compatibleRole)
609
+ return false;
570
610
  const sameContent = localAsset.contentSha256 === incomingAsset.contentSha256
571
611
  && localAsset.sizeBytes === incomingAsset.sizeBytes;
572
612
  const authoritativeMaterialization = localAsset.storageProvider === 'external'
@@ -584,15 +624,15 @@ function isCompatibleLegacyAttachmentLinks(core, workspaceId, local, incoming) {
584
624
  if (!value || typeof value !== 'object' || Array.isArray(value))
585
625
  return false;
586
626
  const incomingLink = value;
587
- if (localLink.role !== incomingLink.role)
588
- return false;
589
627
  const incomingAsset = store.get(String(incomingLink.assetId || ''), workspaceId);
590
628
  return Boolean(incomingAsset && !incomingAsset.deletedAt
591
629
  && incomingAsset.storageProvider !== 'external'
630
+ && localLink.role === 'reference'
631
+ && incomingLink.role === (incomingAsset.kind === 'image' ? 'image' : 'attachment')
592
632
  && incomingAsset.storageKey === localAsset.storageKey
593
633
  && incomingAsset.sizeBytes >= localAsset.sizeBytes);
594
634
  }));
595
- }) && unmatched.length === 0;
635
+ });
596
636
  return compatible;
597
637
  }
598
638
  function assertLocalInventoryReady(input) {
@@ -981,7 +1021,8 @@ export function applyWorkspaceSyncV3CombinedRepairPage(input) {
981
1021
  const supportedTarget = ((target.domain === 'task' && entry.projection === 'task/root-v1')
982
1022
  || (target.domain === 'task-comments' && entry.projection === 'task-comments/full-v1')
983
1023
  || (target.domain === 'task-attachment-links'
984
- && entry.projection === 'task-attachment-links/full-v1')
1024
+ && (entry.projection === 'task-attachment-links/full-v1'
1025
+ || entry.projection === 'task-attachment-links/full-v2'))
985
1026
  || (target.domain === 'entity-event' && entry.projection === 'entity-event/full-v1'));
986
1027
  if (!supportedTarget) {
987
1028
  throw new Error('Targeted workspace sync recovery does not support this projection.');
@@ -7,6 +7,7 @@ export declare function prepareWorkspaceSyncV3CombinedRepairSnapshot(input: {
7
7
  nestedCoverage?: boolean;
8
8
  workflowCoverage?: boolean;
9
9
  planningOrderCoverage?: boolean;
10
+ taskCoverCoverage?: boolean;
10
11
  coveredLegacyWritesFenced?: boolean;
11
12
  }): {
12
13
  highWatermark: string;
@@ -35,6 +36,12 @@ export declare function prepareWorkspaceSyncV3PlanningOrderRepairSnapshot(input:
35
36
  now?: string;
36
37
  coveredLegacyWritesFenced?: boolean;
37
38
  }): ReturnType<typeof prepareWorkspaceSyncV3CombinedRepairSnapshot>;
39
+ export declare function prepareWorkspaceSyncV3TaskCoverRepairSnapshot(input: {
40
+ core: TaskforceCore;
41
+ workspaceId: string;
42
+ now?: string;
43
+ coveredLegacyWritesFenced?: boolean;
44
+ }): ReturnType<typeof prepareWorkspaceSyncV3CombinedRepairSnapshot>;
38
45
  export declare function ensureWorkspaceSyncV3CombinedRepairBaselines(input: {
39
46
  core: TaskforceCore;
40
47
  workspaceId: string;
@@ -3,11 +3,12 @@ import { serializeInitiativeForSync, serializeWorkstreamForSync } from '../plann
3
3
  import { serializeTaskForSync } from '../taskSyncPayload.js';
4
4
  import { canonicalWorkspaceSyncJson } from './canonicalWorkspaceSyncJson.js';
5
5
  import { WORKSPACE_SYNC_COMBINED_PROJECTION, fingerprintWorkspaceSyncPayload, WORKSPACE_SYNC_CONTRACT_VERSION, WorkspaceSyncRevisionConflictError, } from './syncDurabilityStore.js';
6
- import { buildWorkspaceSyncV3CombinedRepairSnapshot, buildWorkspaceSyncV3CombinedRepairSnapshotFromLockedCandidates, buildWorkspaceSyncV3NestedRepairSnapshot, buildWorkspaceSyncV3PlanningOrderRepairSnapshot, buildWorkspaceSyncV3WorkflowRepairSnapshot, listWorkspaceSyncV3CombinedRepairCandidates, listWorkspaceSyncV3NestedRepairCandidates, listWorkspaceSyncV3PlanningOrderRepairCandidates, listWorkspaceSyncV3WorkflowRepairCandidates, } from './workspaceSyncV3CombinedRepairSnapshot.js';
6
+ import { buildWorkspaceSyncV3CombinedRepairSnapshot, buildWorkspaceSyncV3CombinedRepairSnapshotFromLockedCandidates, buildWorkspaceSyncV3NestedRepairSnapshot, buildWorkspaceSyncV3PlanningOrderRepairSnapshot, buildWorkspaceSyncV3TaskCoverRepairSnapshot, buildWorkspaceSyncV3WorkflowRepairSnapshot, listWorkspaceSyncV3CombinedRepairCandidates, listWorkspaceSyncV3NestedRepairCandidates, listWorkspaceSyncV3PlanningOrderRepairCandidates, listWorkspaceSyncV3TaskCoverRepairCandidates, listWorkspaceSyncV3WorkflowRepairCandidates, } from './workspaceSyncV3CombinedRepairSnapshot.js';
7
7
  import { WORKSPACE_SYNC_V3_COMBINED_COVERAGE_PROFILE } from './workspaceSyncV3CombinedCoverage.js';
8
8
  import { WORKSPACE_SYNC_V3_NESTED_COVERAGE_PROFILE } from './workspaceSyncV3NestedCoverage.js';
9
9
  import { WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_PROFILE } from './workspaceSyncV3WorkflowCoverage.js';
10
10
  import { WORKSPACE_SYNC_V3_PLANNING_ORDER_COVERAGE_PROFILE } from './workspaceSyncV3PlanningOrderCoverage.js';
11
+ import { WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_PROFILE } from './workspaceSyncV3TaskCoverCoverage.js';
11
12
  import { serializeWorkspaceSyncV3TaskAttachmentLinksPayload, serializeWorkspaceSyncV3TaskCommentsPayload, } from './workspaceSyncV3NestedTaskCodecs.js';
12
13
  import { projectWorkspaceSyncV3NestedTaskJournalRow } from './workspaceSyncV3NestedTaskProjection.js';
13
14
  import { serializeTaskRelationshipForSync } from './workspaceSyncV3TaskRelationshipProjection.js';
@@ -262,11 +263,13 @@ export function prepareWorkspaceSyncV3CombinedRepairSnapshot(input) {
262
263
  const lockCompletedAt = Date.now();
263
264
  const candidates = input.workflowCoverage
264
265
  ? listWorkspaceSyncV3WorkflowRepairCandidates(input.core, workspaceId)
265
- : input.planningOrderCoverage
266
- ? listWorkspaceSyncV3PlanningOrderRepairCandidates(input.core, workspaceId)
267
- : input.nestedCoverage
268
- ? listWorkspaceSyncV3NestedRepairCandidates(input.core, workspaceId)
269
- : listWorkspaceSyncV3CombinedRepairCandidates(input.core, workspaceId);
266
+ : input.taskCoverCoverage
267
+ ? listWorkspaceSyncV3TaskCoverRepairCandidates(input.core, workspaceId)
268
+ : input.planningOrderCoverage
269
+ ? listWorkspaceSyncV3PlanningOrderRepairCandidates(input.core, workspaceId)
270
+ : input.nestedCoverage
271
+ ? listWorkspaceSyncV3NestedRepairCandidates(input.core, workspaceId)
272
+ : listWorkspaceSyncV3CombinedRepairCandidates(input.core, workspaceId);
270
273
  const inventoryCompletedAt = Date.now();
271
274
  const keys = candidates.map((candidate) => `${candidate.domain}\0${candidate.entityId}`);
272
275
  if (new Set(keys).size !== keys.length)
@@ -550,11 +553,13 @@ export function prepareWorkspaceSyncV3CombinedRepairSnapshot(input) {
550
553
  const baselineWritesCompletedAt = Date.now();
551
554
  const profile = input.workflowCoverage
552
555
  ? WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_PROFILE
553
- : input.planningOrderCoverage
554
- ? WORKSPACE_SYNC_V3_PLANNING_ORDER_COVERAGE_PROFILE
555
- : input.nestedCoverage
556
- ? WORKSPACE_SYNC_V3_NESTED_COVERAGE_PROFILE
557
- : WORKSPACE_SYNC_V3_COMBINED_COVERAGE_PROFILE;
556
+ : input.taskCoverCoverage
557
+ ? WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_PROFILE
558
+ : input.planningOrderCoverage
559
+ ? WORKSPACE_SYNC_V3_PLANNING_ORDER_COVERAGE_PROFILE
560
+ : input.nestedCoverage
561
+ ? WORKSPACE_SYNC_V3_NESTED_COVERAGE_PROFILE
562
+ : WORKSPACE_SYNC_V3_COMBINED_COVERAGE_PROFILE;
558
563
  const activeOwner = db.prepare(`
559
564
  SELECT 1 AS active
560
565
  FROM workspace_sync_projection_state
@@ -576,14 +581,17 @@ export function prepareWorkspaceSyncV3CombinedRepairSnapshot(input) {
576
581
  nestedCoverage: input.nestedCoverage === true,
577
582
  workflowCoverage: input.workflowCoverage === true,
578
583
  planningOrderCoverage: input.planningOrderCoverage === true,
584
+ taskCoverCoverage: input.taskCoverCoverage === true,
579
585
  })
580
586
  : input.workflowCoverage
581
587
  ? buildWorkspaceSyncV3WorkflowRepairSnapshot({ core: input.core, workspaceId })
582
- : input.planningOrderCoverage
583
- ? buildWorkspaceSyncV3PlanningOrderRepairSnapshot({ core: input.core, workspaceId })
584
- : input.nestedCoverage
585
- ? buildWorkspaceSyncV3NestedRepairSnapshot({ core: input.core, workspaceId })
586
- : buildWorkspaceSyncV3CombinedRepairSnapshot({ core: input.core, workspaceId });
588
+ : input.taskCoverCoverage
589
+ ? buildWorkspaceSyncV3TaskCoverRepairSnapshot({ core: input.core, workspaceId })
590
+ : input.planningOrderCoverage
591
+ ? buildWorkspaceSyncV3PlanningOrderRepairSnapshot({ core: input.core, workspaceId })
592
+ : input.nestedCoverage
593
+ ? buildWorkspaceSyncV3NestedRepairSnapshot({ core: input.core, workspaceId })
594
+ : buildWorkspaceSyncV3CombinedRepairSnapshot({ core: input.core, workspaceId });
587
595
  const snapshotCompletedAt = Date.now();
588
596
  if (snapshot.snapshotSequence !== highWatermark) {
589
597
  throw new Error('Combined repair baseline snapshot sequence changed while locked.');
@@ -591,8 +599,9 @@ export function prepareWorkspaceSyncV3CombinedRepairSnapshot(input) {
591
599
  console.info('[Taskforce Sync Repair Baseline Timing]', JSON.stringify({
592
600
  workspaceId,
593
601
  coverage: input.workflowCoverage ? 'workflow'
594
- : input.planningOrderCoverage ? 'planning-order'
595
- : input.nestedCoverage ? 'nested' : 'combined',
602
+ : input.taskCoverCoverage ? 'task-cover'
603
+ : input.planningOrderCoverage ? 'planning-order'
604
+ : input.nestedCoverage ? 'nested' : 'combined',
596
605
  candidates: candidates.length,
597
606
  lock: lockCompletedAt - startedAt,
598
607
  inventory: inventoryCompletedAt - lockCompletedAt,
@@ -615,6 +624,9 @@ export function prepareWorkspaceSyncV3WorkflowRepairSnapshot(input) {
615
624
  export function prepareWorkspaceSyncV3PlanningOrderRepairSnapshot(input) {
616
625
  return prepareWorkspaceSyncV3CombinedRepairSnapshot({ ...input, planningOrderCoverage: true });
617
626
  }
627
+ export function prepareWorkspaceSyncV3TaskCoverRepairSnapshot(input) {
628
+ return prepareWorkspaceSyncV3CombinedRepairSnapshot({ ...input, taskCoverCoverage: true });
629
+ }
618
630
  export function ensureWorkspaceSyncV3CombinedRepairBaselines(input) {
619
631
  const { snapshot: _snapshot, ...result } = prepareWorkspaceSyncV3CombinedRepairSnapshot(input);
620
632
  return result;
@@ -3,6 +3,7 @@ import { WORKSPACE_SYNC_V3_COMBINED_COVERAGE_PROFILE } from './workspaceSyncV3Co
3
3
  import { WORKSPACE_SYNC_V3_NESTED_COVERAGE_PROFILE } from './workspaceSyncV3NestedCoverage.js';
4
4
  import { WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_PROFILE } from './workspaceSyncV3WorkflowCoverage.js';
5
5
  import { WORKSPACE_SYNC_V3_PLANNING_ORDER_COVERAGE_PROFILE } from './workspaceSyncV3PlanningOrderCoverage.js';
6
+ import { WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_PROFILE } from './workspaceSyncV3TaskCoverCoverage.js';
6
7
  import { type WorkspaceSyncV3FeedEntry } from './workspaceSyncV3Feed.js';
7
8
  import { type WorkspaceSyncV3FeedCursorKeyring } from './workspaceSyncV3FeedCursorKeys.js';
8
9
  export interface WorkspaceSyncV3CombinedRepairCursor {
@@ -21,7 +22,7 @@ export interface WorkspaceSyncV3CombinedRepairPage {
21
22
  success: true;
22
23
  protocolVersion: 3;
23
24
  workspaceId: string;
24
- coverage: typeof WORKSPACE_SYNC_V3_COMBINED_COVERAGE_PROFILE | typeof WORKSPACE_SYNC_V3_NESTED_COVERAGE_PROFILE | typeof WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_PROFILE | typeof WORKSPACE_SYNC_V3_PLANNING_ORDER_COVERAGE_PROFILE;
25
+ coverage: typeof WORKSPACE_SYNC_V3_COMBINED_COVERAGE_PROFILE | typeof WORKSPACE_SYNC_V3_NESTED_COVERAGE_PROFILE | typeof WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_PROFILE | typeof WORKSPACE_SYNC_V3_PLANNING_ORDER_COVERAGE_PROFILE | typeof WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_PROFILE;
25
26
  snapshotId: string;
26
27
  snapshotSequence: string;
27
28
  expiresAt: string;
@@ -47,6 +48,8 @@ export declare function decodeWorkspaceSyncV3CombinedRepairCursor(raw: string |
47
48
  export declare function decodeWorkspaceSyncV3NestedRepairCursor(raw: string | null | undefined, keyring: WorkspaceSyncV3FeedCursorKeyring): WorkspaceSyncV3CombinedRepairCursor | null;
48
49
  export declare function decodeWorkspaceSyncV3WorkflowRepairCursor(raw: string | null | undefined, keyring: WorkspaceSyncV3FeedCursorKeyring): WorkspaceSyncV3CombinedRepairCursor | null;
49
50
  export declare function decodeWorkspaceSyncV3PlanningOrderRepairCursor(raw: string | null | undefined, keyring: WorkspaceSyncV3FeedCursorKeyring): WorkspaceSyncV3CombinedRepairCursor | null;
51
+ export declare function decodeWorkspaceSyncV3TaskCoverRepairCursor(raw: string | null | undefined, keyring: WorkspaceSyncV3FeedCursorKeyring): WorkspaceSyncV3CombinedRepairCursor | null;
52
+ export declare const WORKSPACE_SYNC_REPAIR_SNAPSHOT_CLEANUP_BATCH_SIZE = 500;
50
53
  export declare function buildWorkspaceSyncV3CombinedRepairPage(input: {
51
54
  core: TaskforceCore;
52
55
  workspaceId: string;
@@ -59,8 +62,10 @@ export declare function buildWorkspaceSyncV3CombinedRepairPage(input: {
59
62
  nestedCoverage?: boolean;
60
63
  workflowCoverage?: boolean;
61
64
  planningOrderCoverage?: boolean;
65
+ taskCoverCoverage?: boolean;
62
66
  coveredLegacyWritesFenced?: boolean;
63
67
  }): WorkspaceSyncV3CombinedRepairPage;
64
- export declare function buildWorkspaceSyncV3NestedRepairPage(input: Omit<Parameters<typeof buildWorkspaceSyncV3CombinedRepairPage>[0], 'nestedCoverage' | 'workflowCoverage' | 'planningOrderCoverage'>): WorkspaceSyncV3CombinedRepairPage;
65
- export declare function buildWorkspaceSyncV3WorkflowRepairPage(input: Omit<Parameters<typeof buildWorkspaceSyncV3CombinedRepairPage>[0], 'nestedCoverage' | 'workflowCoverage' | 'planningOrderCoverage'>): WorkspaceSyncV3CombinedRepairPage;
66
- export declare function buildWorkspaceSyncV3PlanningOrderRepairPage(input: Omit<Parameters<typeof buildWorkspaceSyncV3CombinedRepairPage>[0], 'nestedCoverage' | 'workflowCoverage' | 'planningOrderCoverage'>): WorkspaceSyncV3CombinedRepairPage;
68
+ export declare function buildWorkspaceSyncV3NestedRepairPage(input: Omit<Parameters<typeof buildWorkspaceSyncV3CombinedRepairPage>[0], 'nestedCoverage' | 'workflowCoverage' | 'planningOrderCoverage' | 'taskCoverCoverage'>): WorkspaceSyncV3CombinedRepairPage;
69
+ export declare function buildWorkspaceSyncV3WorkflowRepairPage(input: Omit<Parameters<typeof buildWorkspaceSyncV3CombinedRepairPage>[0], 'nestedCoverage' | 'workflowCoverage' | 'planningOrderCoverage' | 'taskCoverCoverage'>): WorkspaceSyncV3CombinedRepairPage;
70
+ export declare function buildWorkspaceSyncV3PlanningOrderRepairPage(input: Omit<Parameters<typeof buildWorkspaceSyncV3CombinedRepairPage>[0], 'nestedCoverage' | 'workflowCoverage' | 'planningOrderCoverage' | 'taskCoverCoverage'>): WorkspaceSyncV3CombinedRepairPage;
71
+ export declare function buildWorkspaceSyncV3TaskCoverRepairPage(input: Omit<Parameters<typeof buildWorkspaceSyncV3CombinedRepairPage>[0], 'nestedCoverage' | 'workflowCoverage' | 'planningOrderCoverage' | 'taskCoverCoverage'>): WorkspaceSyncV3CombinedRepairPage;
@@ -1,11 +1,12 @@
1
1
  import { createHmac, randomUUID, timingSafeEqual } from 'crypto';
2
2
  import { canonicalWorkspaceSyncJson } from './canonicalWorkspaceSyncJson.js';
3
3
  import { decodeCanonicalWorkspaceSyncBase64Url } from './workspaceSyncV3CursorEncoding.js';
4
- import { prepareWorkspaceSyncV3CombinedRepairSnapshot, prepareWorkspaceSyncV3NestedRepairSnapshot, prepareWorkspaceSyncV3PlanningOrderRepairSnapshot, prepareWorkspaceSyncV3WorkflowRepairSnapshot, } from './workspaceSyncV3CombinedRepairBaseline.js';
4
+ import { prepareWorkspaceSyncV3CombinedRepairSnapshot, prepareWorkspaceSyncV3NestedRepairSnapshot, prepareWorkspaceSyncV3PlanningOrderRepairSnapshot, prepareWorkspaceSyncV3TaskCoverRepairSnapshot, prepareWorkspaceSyncV3WorkflowRepairSnapshot, } from './workspaceSyncV3CombinedRepairBaseline.js';
5
5
  import { validateWorkspaceSyncV3CombinedFeedEntry, WORKSPACE_SYNC_V3_COMBINED_COVERAGE_PROFILE, } from './workspaceSyncV3CombinedCoverage.js';
6
6
  import { validateWorkspaceSyncV3NestedCoverageFeedEntry, WORKSPACE_SYNC_V3_NESTED_COVERAGE_PROFILE, } from './workspaceSyncV3NestedCoverage.js';
7
7
  import { validateWorkspaceSyncV3WorkflowCoverageFeedEntry, WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_PROFILE, } from './workspaceSyncV3WorkflowCoverage.js';
8
8
  import { validateWorkspaceSyncV3PlanningOrderCoverageFeedEntry, WORKSPACE_SYNC_V3_PLANNING_ORDER_COVERAGE_PROFILE, } from './workspaceSyncV3PlanningOrderCoverage.js';
9
+ import { validateWorkspaceSyncV3TaskCoverCoverageFeedEntry, WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_PROFILE, } from './workspaceSyncV3TaskCoverCoverage.js';
9
10
  import { createWorkspaceSyncV3FeedResumeCursor, WorkspaceSyncV3FeedOperationTooLargeError, } from './workspaceSyncV3Feed.js';
10
11
  import { findWorkspaceSyncV3FeedCursorVerificationKey, } from './workspaceSyncV3FeedCursorKeys.js';
11
12
  import { WORKSPACE_SYNC_COMBINED_PROJECTION, WORKSPACE_SYNC_CONTRACT_VERSION, } from './syncDurabilityStore.js';
@@ -95,14 +96,19 @@ export function decodeWorkspaceSyncV3WorkflowRepairCursor(raw, keyring) {
95
96
  export function decodeWorkspaceSyncV3PlanningOrderRepairCursor(raw, keyring) {
96
97
  return decodeRepairCursor(raw, keyring, WORKSPACE_SYNC_V3_PLANNING_ORDER_COVERAGE_PROFILE);
97
98
  }
99
+ export function decodeWorkspaceSyncV3TaskCoverRepairCursor(raw, keyring) {
100
+ return decodeRepairCursor(raw, keyring, WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_PROFILE);
101
+ }
98
102
  function repairProfile(coverage) {
99
103
  return coverage === 'workflow'
100
104
  ? WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_PROFILE
101
- : coverage === 'planning-order'
102
- ? WORKSPACE_SYNC_V3_PLANNING_ORDER_COVERAGE_PROFILE
103
- : coverage === 'nested'
104
- ? WORKSPACE_SYNC_V3_NESTED_COVERAGE_PROFILE
105
- : WORKSPACE_SYNC_V3_COMBINED_COVERAGE_PROFILE;
105
+ : coverage === 'task-cover'
106
+ ? WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_PROFILE
107
+ : coverage === 'planning-order'
108
+ ? WORKSPACE_SYNC_V3_PLANNING_ORDER_COVERAGE_PROFILE
109
+ : coverage === 'nested'
110
+ ? WORKSPACE_SYNC_V3_NESTED_COVERAGE_PROFILE
111
+ : WORKSPACE_SYNC_V3_COMBINED_COVERAGE_PROFILE;
106
112
  }
107
113
  function containsCurrentEntityEventInventory(input) {
108
114
  if (input.coverage === 'combined')
@@ -140,27 +146,70 @@ function containsCurrentEntityEventInventory(input) {
140
146
  AND entry.domain = 'entity-event'
141
147
  AND entry.entity_id = event.id
142
148
  )
149
+ AND NOT EXISTS (
150
+ SELECT 1
151
+ FROM workspace_sync_journal journal
152
+ WHERE journal.tenant_id = event.tenant_id
153
+ AND journal.workspace_id = event.workspace_id
154
+ AND journal.domain = 'entity-event'
155
+ AND journal.entity_id = event.id
156
+ -- Later sequenced events are delivered after the immutable
157
+ -- repair boundary; only unsequenced legacy adoption makes the
158
+ -- snapshot incomplete and requires rematerialization.
159
+ AND journal.sequence > ?
160
+ )
143
161
  LIMIT 1
144
- `).get(input.tenantId, input.workspaceId, input.snapshotId);
162
+ `).get(input.tenantId, input.workspaceId, input.snapshotId, input.snapshotSequence);
145
163
  return !missing;
146
164
  }
147
- function cleanupExpired(core, tenantId, workspaceId, now, excludingSnapshotId) {
165
+ export const WORKSPACE_SYNC_REPAIR_SNAPSHOT_CLEANUP_BATCH_SIZE = 500;
166
+ function cleanupExpiredBestEffort(core, tenantId, workspaceId, now, excludingSnapshotId) {
148
167
  const db = core.getDatabaseAdapter();
149
168
  const exclusion = excludingSnapshotId ? ' AND snapshot_id <> ?' : '';
150
169
  const args = excludingSnapshotId
151
170
  ? [tenantId, workspaceId, now, excludingSnapshotId]
152
171
  : [tenantId, workspaceId, now];
153
- db.prepare(`
154
- DELETE FROM workspace_sync_repair_snapshot_entries
155
- WHERE tenant_id = ? AND workspace_id = ? AND snapshot_id IN (
156
- SELECT snapshot_id FROM workspace_sync_repair_snapshots
157
- WHERE tenant_id = ? AND workspace_id = ? AND expires_at <= ?${exclusion}
158
- )
159
- `).run(tenantId, workspaceId, ...args);
160
- db.prepare(`
161
- DELETE FROM workspace_sync_repair_snapshots
162
- WHERE tenant_id = ? AND workspace_id = ? AND expires_at <= ?${exclusion}
163
- `).run(...args);
172
+ try {
173
+ db.transaction(() => {
174
+ const expired = db.prepare(`
175
+ SELECT snapshot_id
176
+ FROM workspace_sync_repair_snapshots
177
+ WHERE tenant_id = ? AND workspace_id = ? AND expires_at <= ?${exclusion}
178
+ ORDER BY expires_at ASC, snapshot_id ASC
179
+ LIMIT 1
180
+ `).get(...args);
181
+ const snapshotId = String(expired?.snapshot_id || '').trim();
182
+ if (!snapshotId)
183
+ return;
184
+ db.prepare(`
185
+ DELETE FROM workspace_sync_repair_snapshot_entries
186
+ WHERE tenant_id = ? AND workspace_id = ? AND snapshot_id = ?
187
+ AND entry_index IN (
188
+ SELECT entry_index
189
+ FROM workspace_sync_repair_snapshot_entries
190
+ WHERE tenant_id = ? AND workspace_id = ? AND snapshot_id = ?
191
+ ORDER BY entry_index ASC
192
+ LIMIT ?
193
+ )
194
+ `).run(tenantId, workspaceId, snapshotId, tenantId, workspaceId, snapshotId, WORKSPACE_SYNC_REPAIR_SNAPSHOT_CLEANUP_BATCH_SIZE);
195
+ db.prepare(`
196
+ DELETE FROM workspace_sync_repair_snapshots
197
+ WHERE tenant_id = ? AND workspace_id = ? AND snapshot_id = ? AND expires_at <= ?
198
+ AND NOT EXISTS (
199
+ SELECT 1 FROM workspace_sync_repair_snapshot_entries
200
+ WHERE tenant_id = ? AND workspace_id = ? AND snapshot_id = ?
201
+ )
202
+ `).run(tenantId, workspaceId, snapshotId, now, tenantId, workspaceId, snapshotId);
203
+ })();
204
+ }
205
+ catch (error) {
206
+ // Expired snapshot removal is opportunistic maintenance. A cleanup
207
+ // timeout must not invalidate an otherwise valid repair response.
208
+ console.warn('[Taskforce Sync Repair Cleanup Deferred]', JSON.stringify({
209
+ workspaceId,
210
+ error: String(error?.message || error),
211
+ }));
212
+ }
164
213
  }
165
214
  function persistMaterialization(input) {
166
215
  const db = input.core.getDatabaseAdapter();
@@ -225,6 +274,7 @@ function readMetadata(input) {
225
274
  tenantId: input.tenantId,
226
275
  workspaceId: input.workspaceId,
227
276
  snapshotId: input.cursor.snapshotId,
277
+ snapshotSequence: input.cursor.snapshotSequence,
228
278
  coverage: input.coverage,
229
279
  })) {
230
280
  throw new WorkspaceSyncV3CombinedRepairSnapshotUnavailableError();
@@ -275,6 +325,7 @@ function readReusableMetadata(input) {
275
325
  tenantId: input.tenantId,
276
326
  workspaceId: input.workspaceId,
277
327
  snapshotId: String(row.snapshot_id),
328
+ snapshotSequence: sequence(row.snapshot_sequence, 'Combined repair snapshot sequence'),
278
329
  coverage: input.coverage,
279
330
  }))
280
331
  return null;
@@ -306,11 +357,13 @@ function mapEntry(row, coverage) {
306
357
  };
307
358
  (coverage === 'workflow'
308
359
  ? validateWorkspaceSyncV3WorkflowCoverageFeedEntry
309
- : coverage === 'planning-order'
310
- ? validateWorkspaceSyncV3PlanningOrderCoverageFeedEntry
311
- : coverage === 'nested'
312
- ? validateWorkspaceSyncV3NestedCoverageFeedEntry
313
- : validateWorkspaceSyncV3CombinedFeedEntry)(entry);
360
+ : coverage === 'task-cover'
361
+ ? validateWorkspaceSyncV3TaskCoverCoverageFeedEntry
362
+ : coverage === 'planning-order'
363
+ ? validateWorkspaceSyncV3PlanningOrderCoverageFeedEntry
364
+ : coverage === 'nested'
365
+ ? validateWorkspaceSyncV3NestedCoverageFeedEntry
366
+ : validateWorkspaceSyncV3CombinedFeedEntry)(entry);
314
367
  return entry;
315
368
  }
316
369
  function finalizePage(input) {
@@ -369,22 +422,15 @@ export function buildWorkspaceSyncV3CombinedRepairPage(input) {
369
422
  const db = input.core.getDatabaseAdapter();
370
423
  const coverage = input.workflowCoverage
371
424
  ? 'workflow'
372
- : input.planningOrderCoverage
373
- ? 'planning-order'
374
- : input.nestedCoverage
375
- ? 'nested'
376
- : 'combined';
425
+ : input.taskCoverCoverage
426
+ ? 'task-cover'
427
+ : input.planningOrderCoverage
428
+ ? 'planning-order'
429
+ : input.nestedCoverage
430
+ ? 'nested'
431
+ : 'combined';
377
432
  if (input.cursor && Date.parse(input.cursor.expiresAt) <= Date.parse(now)) {
378
- db.transaction(() => {
379
- db.prepare(`DELETE FROM workspace_sync_repair_snapshot_entries
380
- WHERE tenant_id = ? AND workspace_id = ? AND snapshot_id = ? AND EXISTS (
381
- SELECT 1 FROM workspace_sync_repair_snapshots
382
- WHERE tenant_id = ? AND workspace_id = ? AND snapshot_id = ? AND expires_at <= ?
383
- )`).run(tenantId, workspaceId, input.cursor.snapshotId, tenantId, workspaceId, input.cursor.snapshotId, now);
384
- db.prepare(`DELETE FROM workspace_sync_repair_snapshots
385
- WHERE tenant_id = ? AND workspace_id = ? AND snapshot_id = ? AND expires_at <= ?`)
386
- .run(tenantId, workspaceId, input.cursor.snapshotId, now);
387
- })();
433
+ cleanupExpiredBestEffort(input.core, tenantId, workspaceId, now);
388
434
  throw new WorkspaceSyncV3CombinedRepairSnapshotUnavailableError();
389
435
  }
390
436
  let insertedBaselineEntities = 0;
@@ -393,17 +439,17 @@ export function buildWorkspaceSyncV3CombinedRepairPage(input) {
393
439
  let metadata;
394
440
  let nextIndex;
395
441
  if (input.cursor) {
442
+ cleanupExpiredBestEffort(input.core, tenantId, workspaceId, now, input.cursor.snapshotId);
396
443
  metadata = db.transaction(() => {
397
- const current = readMetadata({
444
+ return readMetadata({
398
445
  core: input.core, tenantId, workspaceId, cursor: input.cursor, now,
399
446
  coverage,
400
447
  });
401
- cleanupExpired(input.core, tenantId, workspaceId, now, current.snapshotId);
402
- return current;
403
448
  })();
404
449
  nextIndex = input.cursor.nextIndex;
405
450
  }
406
451
  else {
452
+ cleanupExpiredBestEffort(input.core, tenantId, workspaceId, now);
407
453
  const materialized = db.transaction(() => {
408
454
  // Serialize cursorless materialization and reuse decisions with
409
455
  // durable writers and competing repair requests.
@@ -413,7 +459,6 @@ export function buildWorkspaceSyncV3CombinedRepairPage(input) {
413
459
  ON CONFLICT (tenant_id, workspace_id) DO UPDATE SET updated_at = excluded.updated_at
414
460
  RETURNING CAST(last_sequence AS TEXT) AS last_sequence
415
461
  `).get(tenantId, workspaceId, now);
416
- cleanupExpired(input.core, tenantId, workspaceId, now);
417
462
  const reusable = readReusableMetadata({
418
463
  core: input.core, tenantId, workspaceId, now,
419
464
  coverage,
@@ -428,11 +473,14 @@ export function buildWorkspaceSyncV3CombinedRepairPage(input) {
428
473
  : coverage === 'planning-order'
429
474
  ? prepareWorkspaceSyncV3PlanningOrderRepairSnapshot({ core: input.core, workspaceId, now,
430
475
  coveredLegacyWritesFenced: input.coveredLegacyWritesFenced })
431
- : coverage === 'nested'
432
- ? prepareWorkspaceSyncV3NestedRepairSnapshot({ core: input.core, workspaceId, now,
476
+ : coverage === 'task-cover'
477
+ ? prepareWorkspaceSyncV3TaskCoverRepairSnapshot({ core: input.core, workspaceId, now,
433
478
  coveredLegacyWritesFenced: input.coveredLegacyWritesFenced })
434
- : prepareWorkspaceSyncV3CombinedRepairSnapshot({ core: input.core, workspaceId, now,
435
- coveredLegacyWritesFenced: input.coveredLegacyWritesFenced });
479
+ : coverage === 'nested'
480
+ ? prepareWorkspaceSyncV3NestedRepairSnapshot({ core: input.core, workspaceId, now,
481
+ coveredLegacyWritesFenced: input.coveredLegacyWritesFenced })
482
+ : prepareWorkspaceSyncV3CombinedRepairSnapshot({ core: input.core, workspaceId, now,
483
+ coveredLegacyWritesFenced: input.coveredLegacyWritesFenced });
436
484
  // Production expiry is sampled at the end of persistence, after
437
485
  // every immutable payload row has committed in the same lock.
438
486
  const materializationStartedAt = input.now
@@ -525,3 +573,6 @@ export function buildWorkspaceSyncV3WorkflowRepairPage(input) {
525
573
  export function buildWorkspaceSyncV3PlanningOrderRepairPage(input) {
526
574
  return buildWorkspaceSyncV3CombinedRepairPage({ ...input, planningOrderCoverage: true });
527
575
  }
576
+ export function buildWorkspaceSyncV3TaskCoverRepairPage(input) {
577
+ return buildWorkspaceSyncV3CombinedRepairPage({ ...input, taskCoverCoverage: true });
578
+ }
@@ -31,6 +31,8 @@ export declare class WorkspaceSyncV3CombinedRepairBaselineRequiredError extends
31
31
  export declare function listWorkspaceSyncV3CombinedRepairCandidates(core: TaskforceCore, workspaceId: string): WorkspaceSyncV3CombinedRepairCandidate[];
32
32
  /** Candidate v4 inventory. The coverage-v3 inventory above intentionally remains unchanged. */
33
33
  export declare function listWorkspaceSyncV3NestedRepairCandidates(core: TaskforceCore, workspaceId: string): WorkspaceSyncV3CombinedRepairCandidate[];
34
+ /** Candidate v7 inventory. It is the v4 family with attachment-link schema v2. */
35
+ export declare function listWorkspaceSyncV3TaskCoverRepairCandidates(core: TaskforceCore, workspaceId: string): WorkspaceSyncV3CombinedRepairCandidate[];
34
36
  /** Candidate v5 inventory. Coverage-v3/v4 inventories intentionally remain unchanged. */
35
37
  export declare function listWorkspaceSyncV3WorkflowRepairCandidates(core: TaskforceCore, workspaceId: string): WorkspaceSyncV3CombinedRepairCandidate[];
36
38
  /** Candidate v6 inventory. Workflow v5 remains an independent dark contract. */
@@ -50,6 +52,7 @@ export declare function buildWorkspaceSyncV3CombinedRepairSnapshotFromLockedCand
50
52
  nestedCoverage?: boolean;
51
53
  workflowCoverage?: boolean;
52
54
  planningOrderCoverage?: boolean;
55
+ taskCoverCoverage?: boolean;
53
56
  }): {
54
57
  snapshotSequence: string;
55
58
  entries: WorkspaceSyncV3FeedEntry[];
@@ -75,4 +78,11 @@ export declare function buildWorkspaceSyncV3PlanningOrderRepairSnapshot(input: {
75
78
  snapshotSequence: string;
76
79
  entries: WorkspaceSyncV3FeedEntry[];
77
80
  };
81
+ export declare function buildWorkspaceSyncV3TaskCoverRepairSnapshot(input: {
82
+ core: TaskforceCore;
83
+ workspaceId: string;
84
+ }): {
85
+ snapshotSequence: string;
86
+ entries: WorkspaceSyncV3FeedEntry[];
87
+ };
78
88
  export {};