feat(tasks): task dependency field in kanban (T-57) - #22
Merged
Conversation
Adds a dependsOn: string[] field to kanban tasks so auto-work (later tasks in the chain) can determine whether a task's prerequisites are resolved before queueing it. This task only builds the data model, API, and UI — no scheduling/engine logic (that's T-64). - packages/protocol: Task.dependsOn (always present), CreateTaskRequest/ UpdateTaskRequest.dependsOn (optional; PATCH replaces the full set). - apps/server/src/db/migrations/007-task-dependencies.sql: task_dependencies join table (task_id, depends_on_task_id) with FK ON DELETE CASCADE so deleting either side of an edge cleans up automatically, plus a CHECK against self-reference at the schema level. - apps/server/src/db/tasks.ts: listTasks batch-loads all dependency edges in one query; getTask/findTaskByDisplayOrId load per-task. createTask/ updateTask validate the dependency set (dedupe, reject self-reference, reject unknown task ids, reject a cycle via BFS over existing edges) before mutating, and updateTask's dependsOn replaces the full set only when the patch includes the key (undefined leaves it untouched). - apps/server/src/routes-tasks.ts: POST/PATCH /tasks validate dependsOn is string[] before hitting the DB layer. - apps/web: TaskModal gained a "Depends on" section — chips showing each dependency's T-<id>, title, and current state (color dot, or a check for a "done"-named state) with a remove button, plus a select to add a new dependency from every other non-archived task. The id-resolution/ filtering logic lives in the new apps/web/src/lib/task-dependencies.ts (resolveDependencyTasks/candidateDependencyTasks) so it has plain unit tests instead of needing a hook-rendering harness — same rationale as T-56's groupModels() extraction. TaskDrawer.tsx is confirmed dead code (no imports anywhere) and was left untouched. Tests: apps/server/src/db/tasks.test.ts gained 11 cases covering default/ explicit/replace/clear/untouched dependsOn, self-reference, unknown id, direct + transitive cycle rejection, list/get round-trip, and delete cascade. apps/web/src/lib/task-dependencies.test.ts covers resolve/ candidate filtering and sort order.
3 tasks
If B depends on A, A now shows a read-only 'Required by' section listing B (and any other tasks that depend on it). Same chip style as 'Depends on' but no remove button — the relationship is owned by the dependent, not the blocker. - resolveDependentTasks(): new pure helper in task-dependencies.ts (tasks whose dependsOn[] includes task.id, sorted by displayId) - 5 new unit tests covering: basic resolution, empty case, sort order, archived dependents included, self-exclusion guard - TaskModal: useMemo(dependentTasks), section rendered only when non-empty
jaesbit
added a commit
that referenced
this pull request
Jul 6, 2026
Adds an autoWork: boolean opt-in flag to kanban tasks so the auto-work engine (T-64) only ever considers tasks the user explicitly marked eligible. Not every card should be touched by unattended automation — this ticket only builds the data model, API, and UI toggle; no scheduling logic. Stacked on feat/t57-task-dependencies (PR #22) since both tickets touch the same task protocol/DB/routes/UI files — this diff is the incremental change on top of T-57's dependsOn work, not a rebase onto main. - packages/protocol: Task.autoWork (always present, default false), CreateTaskRequest/UpdateTaskRequest.autoWork (optional). - apps/server/src/db/migrations/008-task-autowork.sql: ALTER TABLE tasks ADD COLUMN auto_work INTEGER NOT NULL DEFAULT 0, same pattern as 006-task-priority.sql. Indexed for the future T-64 engine query (WHERE auto_work = 1). - apps/server/src/db/tasks.ts: TaskRow/rowToTask carry auto_work through every read path (listTasks, getTask, findTaskByDisplayOrId). createTask/updateTask accept autoWork, persisted independently of the dependsOn set added by T-57. - apps/server/src/routes-tasks.ts: POST/PATCH /tasks validate autoWork is a boolean before hitting the DB layer, same shape as the existing dependsOn/priority checks. - apps/web: TaskCard shows a small Zap indicator next to the priority badge when autoWork is true. TaskModal gained an "Eligible for Auto Work" checkbox in the metadata grid, next to cwd. TaskDrawer.tsx is confirmed dead code (no imports anywhere, per T-57's findings) and was left untouched. Tests: apps/server/src/db/tasks.test.ts gained 6 cases covering default/explicit/toggle/untouched autoWork and independence from dependsOn on create+update+list+get round-trips.
jaesbit
added a commit
that referenced
this pull request
Jul 6, 2026
Adds an autoWork: boolean opt-in flag to kanban tasks so the auto-work engine (T-64) only ever considers tasks the user explicitly marked eligible. Not every card should be touched by unattended automation — this ticket only builds the data model, API, and UI toggle; no scheduling logic. Stacked on feat/t57-task-dependencies (PR #22) since both tickets touch the same task protocol/DB/routes/UI files — this diff is the incremental change on top of T-57's dependsOn work, not a rebase onto main. - packages/protocol: Task.autoWork (always present, default false), CreateTaskRequest/UpdateTaskRequest.autoWork (optional). - apps/server/src/db/migrations/008-task-autowork.sql: ALTER TABLE tasks ADD COLUMN auto_work INTEGER NOT NULL DEFAULT 0, same pattern as 006-task-priority.sql. Indexed for the future T-64 engine query (WHERE auto_work = 1). - apps/server/src/db/tasks.ts: TaskRow/rowToTask carry auto_work through every read path (listTasks, getTask, findTaskByDisplayOrId). createTask/updateTask accept autoWork, persisted independently of the dependsOn set added by T-57. - apps/server/src/routes-tasks.ts: POST/PATCH /tasks validate autoWork is a boolean before hitting the DB layer, same shape as the existing dependsOn/priority checks. - apps/web: TaskCard shows a small Zap indicator next to the priority badge when autoWork is true. TaskModal gained an "Eligible for Auto Work" checkbox in the metadata grid, next to cwd. TaskDrawer.tsx is confirmed dead code (no imports anywhere, per T-57's findings) and was left untouched. Tests: apps/server/src/db/tasks.test.ts gained 6 cases covering default/explicit/toggle/untouched autoWork and independence from dependsOn on create+update+list+get round-trips.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Auto-work needs to know which tasks can run without waiting for others. A task with unresolved dependencies must not be queued.
Scope
dependsOn: string[]added to the task protocol (packages/protocol/src/index.ts).007-task-dependencies.sql:task_dependenciesjoin table (task_id,depends_on_task_id), FKON DELETE CASCADEboth ways,CHECK (task_id != depends_on_task_id).GET /tasks,POST /tasks,PATCH /tasks/:idall read/writedependsOn.TaskModal— add/remove deps as chips showingT-<id>, title, and current state (color dot, or a check for a "done"-named state).This is task 1 of an 11-task "Auto Work" chain; later tasks stack their own worktrees/branches on top of
feat/t57-task-dependencies.Non-goals
The "engine skips a blocked task" part of T-57's original acceptance is explicitly deferred to T-64 (not built yet, not in scope here). This PR only ships the data model, API, and UI.
Files changed
packages/protocol/src/index.tsapps/server/src/db/migrations/007-task-dependencies.sql(new)apps/server/src/db/tasks.ts,apps/server/src/db/tasks.test.tsapps/server/src/routes-tasks.tsapps/web/src/components/tasks/TaskModal.tsx,apps/web/src/views/TasksView.tsxapps/web/src/lib/task-dependencies.ts,apps/web/src/lib/task-dependencies.test.ts(new)TaskDrawer.tsx(listed in the ticket's surface area) is confirmed dead code — not imported anywhere in the app — so it was left untouched rather than adding UI to a component nothing renders.Validation
bun run --filter '@omp-deck/protocol' typecheck— cleanbun run --filter '@omp-deck/server' typecheck— cleanbun run --filter '@omp-deck/web' typecheck— cleancd apps/server && bun test— 229/229 pass (11 new dependency cases)cd apps/web && bun test— 149/149 pass (5 new dependency-helper cases)bun run --filter '@omp-deck/web' build— succeeds (pre-existing >500kB chunk warning, unrelated)Acceptance
PATCH /tasks/:id.GET /tasksincludesdependsOnon each task.