Files
ClaudeDo/docs/superpowers/specs/2026-08-11-dependency-chain-display-design.md
T

4.1 KiB

Dependency chain display — Design

Date: 2026-08-11 Status: approved, not implemented

Problem

DependsOnTaskId is invisible in the UI. TaskRowViewModel has no DependsOnTaskId property and TaskRowView.axaml renders nothing for it — a chained task looks exactly like an unrelated one. The execution order the user declared is not readable anywhere in the list.

Target

A chain renders as a group: the head full width, its dependents indented behind a vertical rail, each carrying a small circular step badge on the rail.

┌──────────────────────────────────────────┐
│  chain head (full width, no badge)       │
└──────────────────────────────────────────┘
  ╷ ┌────────────────────────────────────┐
 (1)│  first dependent                   │
  ╷ └────────────────────────────────────┘
  ╷ ┌────────────────────────────────────┐
 (2)│  second                            │
  ╷ └────────────────────────────────────┘
  ╷ ┌────────────────────────────────────┐
 (2)│  parallel to the second            │
  ╷ └────────────────────────────────────┘
  ╷ ┌────────────────────────────────────┐
 (3)│  third                             │
    └────────────────────────────────────┘

Model reading

  • Step number = hop distance from the chain head, not a running counter. DependsOnTaskId is a single FK, so several tasks may share one predecessor → same depth → same number. Two rows showing 2 means "these two are both unblocked by step 1", which is the intended reading.
  • Chain head = a task with no DependsOnTaskId that at least one other task points at. A task with no dependents and no dependency is not a chain and renders exactly as today.
  • Cycles are impossible (TaskStateService.SetDependsOnAsync rejects them), so the depth walk always terminates. Still cap the walk defensively.

Decisions

One indent level only — parent wins. The 24 px indent track already exists for planning children (TaskRowView.axaml:22-28, gated on ShowAsChild). A planning child that also has a DependsOnTaskId keeps the parent indent and shows its chain membership as a small inline chip (after #123) instead of a second indent level. No nesting, no 48 px rows.

The group is pulled together; the head carries it. Chain members are re-ordered to sit directly under their head regardless of SortOrder, so displayed order always equals execution order. Dragging the head moves the whole group; members are not individually draggable.

Head not in view → no orphan rails. Exact precedent exists: ParentInView /ShowAsChild (TaskRowViewModel.cs:75, computed in Regroup at TasksIslandViewModel.cs:543). Same treatment — if the head is filtered out (other list, My Day, completed group), the row renders flat with the after #123 chip instead of a dangling rail.

Badge has no #. If task numbers (2026-08-11-task-numbers-design.md) also land, a row would show a rail badge and a #412 title prefix. The rail badge is a step position, not an identity — render it bare (2), never #2.

Slices

# Slice Depends on
1 VM: DependsOnTaskId + depth/head computation in Regroup, group pull-together, drag semantics
2 View: rail, step badge, after … chip, locale keys 1

Slice 1 exposes the contract Slice 2 binds to: ShowAsChainMember, ChainStep, ChainAfterLabel.