multica-ai / multica-ai/multica

[Feature]: block child issue scheduling until parent issue is completed

Open
#970 2 comments 3 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
Go
Stars
50.4k
Forks
6.5k
Avg merge
1d 36m
Merged PRs (30d)
500

Description

What do you want and why?

Problem

When issues have parent-child relationships (parent_issue_id), the daemon's task scheduler ignores these dependencies entirely. Child issues are scheduled and executed in parallel with their parent issues.

Example scenario:

  • Parent: [Infra] Set up Next.js project (Phase 1 — must complete first)
  • Child: [Feature] Build salary calculator page (Phase 2 — depends on Phase 1)
  • Expected: Child waits for parent to reach done status before starting
  • Actual: Both are picked up and executed simultaneously by agents

This defeats the purpose of the parent/sub-issue hierarchy, which users rely on to model task dependencies.

Root Cause

1. SQL query has no parent-status filter

server/pkg/db/queries/agent.sql:168-171:

-- name: ListPendingTasksByRuntime :many
SELECT * FROM agent_task_queue
WHERE runtime_id = $1 AND status IN ('queued', 'dispatched')
ORDER BY priority DESC, created_at ASC;

The query only filters by runtime_id and task status. It does not join against the issue table to check whether the task's parent issue is complete.

2. ClaimTaskForRuntime has no dependency check

server/internal/service/task.go:211-235:

func (s *TaskService) ClaimTaskForRuntime(ctx context.Context, runtimeID pgtype.UUID) (*db.AgentTaskQueue, error) {
    tasks, err := s.Queries.ListPendingTasksByRuntime(ctx, runtimeID)
    // ... iterates candidates, only checks agent concurrency limit
}

No validation that the candidate task's issue has a completed parent before claiming it.

Proposed solution (optional)
Option A: Filter at the SQL level (recommended)

Modify ListPendingTasksByRuntime to exclude tasks whose issue has an incomplete parent:

-- name: ListPendingTasksByRuntime :many
SELECT atq.* FROM agent_task_queue atq
JOIN issue i ON atq.issue_id = i.id
LEFT JOIN issue parent ON i.parent_issue_id = parent.id
WHERE atq.runtime_id = $1 
  AND atq.status IN ('queued', 'dispatched')
  AND (i.parent_issue_id IS NULL OR parent.status IN ('done', 'cancelled'))
ORDER BY atq.priority DESC, atq.created_at ASC;

Pros: Single query, no extra round-trips, clean
Cons: Requires sqlc regeneration

Option B: Filter at the service level

Add a parent-status check in ClaimTaskForRuntime after fetching candidates:

for _, candidate := range tasks {
    // Check if parent issue is done
    issue, _ := s.Queries.GetIssue(ctx, candidate.IssueID)
    if issue.ParentIssueID.Valid {
        parent, _ := s.Queries.GetIssue(ctx, issue.ParentIssueID)
        if parent.Status != "done" && parent.Status != "cancelled" {
            continue // skip — parent not finished
        }
    }
    // ... existing claim logic
}

Impact

  • Who is affected: All users who set parent/sub-issue relationships expecting sequential execution
  • Severity: Medium — feature exists in UI but doesn't work as expected
  • Scope: server/pkg/db/queries/agent.sql, server/internal/service/task.go, server/pkg/db/ (sqlc generated)

Acceptance Criteria

  • Tasks with a parent issue in todo, in_progress, in_review, or blocked status are NOT scheduled
  • Tasks with a parent issue in done or cancelled status ARE scheduled normally
  • Tasks with no parent issue (parent_issue_id IS NULL) are unaffected
  • Existing tests pass, new test covers the blocking behavior

Pros: No SQL changes
Cons: Extra DB queries per candidate, less efficient

Screenshots / mockups (optional)

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with server/pkg/db/queries/agent.sql and server/internal/service/task.go, following ListPendingTasksByRuntime into ClaimTaskForRuntime. Review the sqlc-generated files under server/pkg/db/ and the existing task tests before choosing the filtering layer. Done means parentless tasks and tasks with done or cancelled parents schedule normally, while tasks with incomplete parents remain blocked and the existing tests still pass.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, postgresql
Domain
backend, databases
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
66/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.