Skip to content

fix(sync): Create subtasks during bulk import and sync pull#122

Closed
dcramer wants to merge 8 commits intomainfrom
fix/subtask-import-sync
Closed

fix(sync): Create subtasks during bulk import and sync pull#122
dcramer wants to merge 8 commits intomainfrom
fix/subtask-import-sync

Conversation

@dcramer
Copy link
Owner

@dcramer dcramer commented Feb 17, 2026

Summary

Supersedes #118. Fixes three broken flows where subtasks embedded in GitHub issue bodies were not being created locally:

  • dex import --all — only created parent tasks, skipped subtasks
  • dex import #N --update — only updated the parent task, ignored new subtasks in the body
  • dex sync pull path — when remote was newer, subtasks not found locally were silently skipped

Changes

  • Extract shared importSubtasksFromIssueBody helper for create + update of subtasks during import
  • Extend reconcileSubtasksFromRemote to return needsCreation/createData for subtasks that exist remotely but not locally
  • Fix saveMetadata filter to include pulledFromRemote results (previously filtered out by skipped check)
  • Fix metadata merge bug in subtask update path — was doing full replacement, now merges to preserve integration metadata
  • Improve createData type from Record<string, unknown> to CreateTaskInput for compile-time safety
  • Add started_at to import path, allow nullable result/metadata in UpdateTaskInput
  • Add end-to-end tests for sync pull subtask creation and import subtask update

Test plan

  • All 907 tests pass (905 existing + 2 new)
  • Build passes with no type errors
  • dex import --all creates subtasks from issue bodies
  • dex import #N --update creates new subtasks and updates existing ones
  • dex sync pull path creates subtasks that only exist remotely
  • Metadata is merged (not replaced) when updating existing subtasks

🤖 Generated with Claude Code

adnankurt16 and others added 8 commits February 9, 2026 19:21
Subtasks embedded in GitHub issue bodies (as <details> blocks) were only
created during single-issue import. Three flows were broken:

- `dex import --all` only created parent tasks
- `dex import #N --update` only updated the parent task
- `dex sync` pull path skipped subtasks not found locally

Extract importSubtasksFromIssueBody helper from the working single-import
path and reuse it across all import flows. For sync pull, extend SyncResult
with needsCreation/createData fields so reconcileSubtasksFromRemote can
signal that new local subtasks should be created.

Fixes #117

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
reconcileSubtasksFromRemote checked store.tasks for parent existence,
but when multiple nested subtasks are created in the same sync batch,
parents processed earlier in the batch weren't visible. This caused
grandchild subtasks to be flattened to the root task instead of
preserving hierarchy.

Track processed subtask IDs so nested subtasks can resolve parents
that are also being created in the same sync operation.

Fixes part of #119

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
importSubtasksFromIssueBody called service.list({ all: true }) on every
invocation, causing O(n) file reads during bulk import (once per issue).
The task list was already fetched by callers, so pass it through instead
of re-fetching.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…mote results

syncAll results with pulledFromRemote=true were also marked skipped=true
(since nothing was pushed to remote). The saveMetadata loop filtered out
all skipped results, so local updates (completion state, timestamps) and
subtask creation from remote were never applied.

Allow pulledFromRemote results through the filter so that:
- Parent task completion/timestamps are updated from remote
- Subtasks found in remote issue body are created locally

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
started_at was parsed from GitHub issue metadata comments but never
passed to service.create() or service.update(). This caused imported
tasks and subtasks to lose their in-progress state.

Fixed in 4 places:
- importGitHubIssueAsTask (parent task create)
- importSubtasksFromIssueBody (subtask create)
- importSubtasksFromIssueBody (subtask update)
- reconcileSubtasksFromRemote (sync pull createData)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
UpdateTaskInputSchema used .optional() for result and metadata, meaning
only undefined (skip) and string/object (set) were valid. This prevented
clearing these fields via null during import --update.

Added .nullable() to match the pattern already used by parent_id and
started_at. Now undefined = skip, null = clear, value = set.

Removed ?? undefined workarounds in import subtask update path so null
values from remote are properly passed through to clear local fields.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolve conflict in specs/sync.md: keep both Subtask Sync and Labels sections.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix metadata replacement bug in importSubtasksFromIssueBody that would
  wipe integration metadata (github/shortcut keys) when updating existing
  subtasks — now merges with existing metadata
- Change createData type from Record<string, unknown> to CreateTaskInput
  for compile-time type safety, removing unsafe cast in saveMetadata
- Add end-to-end test for sync pull creating subtasks locally
- Add test for --update updating existing subtasks (not just creating)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@vercel
Copy link

vercel bot commented Feb 17, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
dex Ready Ready Preview, Comment Feb 17, 2026 7:41pm

Request Review

@dcramer
Copy link
Owner Author

dcramer commented Feb 17, 2026

Closing in favor of #118 which has been updated directly.

@dcramer dcramer closed this Feb 17, 2026
@dcramer dcramer deleted the fix/subtask-import-sync branch February 17, 2026 19:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments