7.5 KiB
spec, created, status
| spec | created | status |
|---|---|---|
| docs/specs/tasks/requirements/subtask-completion-trigger.md | 2026-06-23 | implemented |
Implementation Plan: Subtask Completion Trigger
Overview
The workflow model already contains on_children_completed, but generic
MCP/kanban subtasks do not synthesize that trigger when their task state reaches
terminal. Implement this by adding active-child completion helpers, preserving
the event shape through API/frontend types, and wiring task.state_changed into
an orchestrator trigger path that applies workflow transitions with normal
on_exit/on_enter behavior. Finish with focused backend tests and one E2E
that proves child task completion advances the parent without polling.
Backend
Task Repository
Files:
apps/backend/internal/task/repository/interface.goapps/backend/internal/task/repository/sqlite/task.goapps/backend/internal/task/repository/task_repository_test.go
Changes:
- Add a repository helper that returns active direct children with fields needed
for completion checks and idempotency, for example:
ListChildCompletionRows(ctx, parentID string) ([]ChildCompletionRow, error). ChildCompletionRowshould includeID,State,Title, andUpdatedAt.- Match
ListChildrenactive semantics:parent_id = ?,archived_at IS NULL, andis_ephemeral = 0. - Treat
COMPLETED,FAILED, andCANCELLEDas terminal.
Reason:
- The generic task layer must not import Office repository helpers, and Office's
current helper omits
FAILEDfrom terminal states.
Workflow Trigger Dispatch
Files:
apps/backend/internal/orchestrator/service.goapps/backend/internal/orchestrator/event_handlers_children_completed.goapps/backend/internal/orchestrator/event_handlers_workflow.goapps/backend/internal/orchestrator/workflow_store.go
Changes:
- Wire
watcher.EventHandlers.OnTaskStateChangedto a new orchestrator handler. - In the handler, ignore events where
parent_idis empty ornew_stateis not terminal. - Load active direct children of the parent and return early until all are terminal.
- Build
engine.OnChildrenCompletedPayloadfrom child rows. - Build a deterministic operation id such as
children_completed:<parentID>:<sorted child id/state/updated_at digest>. - Resolve the parent active session with the existing repository session lookup.
- Evaluate
engine.TriggerOnChildrenCompletedinEvaluateOnlymode and apply transition results through the same transition helper used byon_turn_complete, soon_exit, data persistence, DB step change, andon_enterfire correctly. - If the trigger has only side-effect actions and no transition, mark the derived operation as applied after the engine evaluates callbacks.
Reason:
office/engine_dispatcher.Dispatchercallsengine.HandleTriggerdirectly and does not apply returned transitions. Parent step movement must use the orchestrator transition lifecycle.
Workflow Event DTOs
Files:
apps/backend/internal/task/dto/dto.goapps/backend/internal/task/dto/converters.goapps/backend/internal/task/dto/converters_test.go
Changes:
- Extend
StepEventsDTOto includeon_turn_start,on_exit, and all generic trigger slices, especiallyon_children_completed. - Update
FromWorkflowStepso API responses preserve every non-empty event slice inworkflow_step.events.
Reason:
- Existing converters only return
on_enterandon_turn_complete, which would make configured generic triggers disappear from API consumers.
Frontend
Type Parity
Files:
apps/web/lib/types/workflow-actions.tsapps/web/lib/state/slices/kanban/types.tsapps/web/e2e/helpers/api-client.ts
Changes:
- Add generic workflow action types for
move_to_next,move_to_previous,move_to_step,auto_start_agent,queue_run,queue_run_for_each_participant, andclear_decisions. - Extend
StepEventsandKanbanStepEventswithon_children_completed?: GenericAction[]plus the other already-supported generic trigger names where useful for parity. - Extend E2E API helper workflow-step update typings so tests can configure
on_children_completed.
Reason:
- This feature does not require new visible UI, but TypeScript should accept and preserve workflow event JSON that the backend already supports.
Tests
-
What: active children terminal detection includes
COMPLETED,FAILED, andCANCELLED; non-terminal states block; archived/ephemeral rows are ignored. File:apps/backend/internal/task/repository/task_repository_test.goHow: SQLite-backed table-driven repository test. -
What: workflow-step DTO conversion preserves
on_children_completed. File:apps/backend/internal/task/dto/converters_test.goHow: unit test ondto.FromWorkflowStep. -
What: last direct child terminal state fires one parent
on_children_completedtrigger. File:apps/backend/internal/orchestrator/event_handlers_children_completed_test.goHow: orchestrator unit/integration test with fake engine/repository. -
What: first child terminal state does not fire while siblings remain non-terminal. File:
apps/backend/internal/orchestrator/event_handlers_children_completed_test.goHow: table-driven orchestrator test. -
What: duplicate terminal updates do not duplicate parent actions. File:
apps/backend/internal/orchestrator/event_handlers_children_completed_test.goHow: invoke handler twice with same operation inputs and assert one engine action/transition. -
What: parent
move_to_nextaction uses normal workflow transition lifecycle. File:apps/backend/internal/orchestrator/event_handlers_children_completed_test.goHow: integration-style test asserts persisted parent step andon_enterside effect. -
What: frontend workflow event typings accept
on_children_completed. File: no dedicated unit test unless a nearby type helper exists. How:cd apps && pnpm --filter @kandev/web typecheck.
E2E Tests
- Scenario: GIVEN a parent task has two active children and its current
workflow step defines
on_children_completed, WHEN the first child completes and the second remains non-terminal, THEN the parent stays put. WHEN the second child completes, THEN the parent moves to the configured done step. File:apps/web/e2e/tests/workflow/workflow-children-completed.spec.tsWhat to verify: parent task workflow step changes only after every active direct child is terminal.
Implementation Waves
Wave 1 (parallel):
Wave 2:
Wave 3:
Verification Commands
Format first:
make fmt
Targeted backend tests:
cd apps/backend && go test ./internal/task/repository/... ./internal/task/dto/... ./internal/orchestrator/... ./internal/workflow/engine/...
Frontend typecheck:
cd apps && pnpm --filter @kandev/web typecheck
Focused E2E:
cd apps/web && pnpm e2e workflow-children-completed.spec.ts
Full verification:
make typecheck test lint
Open Questions
None for the first implementation pass. The spec intentionally fixes direct children only, best-effort child summaries, and no automatic parent session creation.