# Execution Semantics for Issue Dependencies and Blockers in Paperclip AI

> Understand execution semantics for issue dependencies and blockers in Paperclip AI. Explore directed-acyclic graphs, hard execution constraints, topological ordering, and actionable items for stalled blockers.

- Repository: [Paperclip/paperclip](https://github.com/paperclipai/paperclip)
- Tags: internals
- Published: 2026-08-12

---

**Paperclip AI implements issue dependencies as a directed-acyclic graph where `blockedBy` edges enforce hard execution constraints, with `workflowSort` providing topological ordering and the `attention` service generating actionable items for stalled blockers.**

This article examines how [Paperclip AI](https://github.com/paperclipai/paperclip) encodes, sorts, and acts on issue blocker relationships across its TypeScript codebase. The execution semantics span three architectural layers: shared type definitions, UI presentation logic, and server-side attention generation.

## Data Model: Encoding Blocker State and Diagnostics

The foundation of Paperclip's execution semantics resides in [[`packages/shared/src/types/issue.ts`](https://github.com/paperclipai/paperclip/blob/main/packages/shared/src/types/issue.ts)](https://github.com/paperclipai/paperclip/blob/master/packages/shared/src/types/issue.ts). This file defines the canonical shape of **blocker attention diagnostics** that flow through the entire system.

### IssueBlockerAttentionState Enum

The `state` field uses a four-value enum to communicate blocker urgency:

- `"none"` – no active dependency concern
- `"covered"` – blocker exists but is being addressed
- `"stalled"` – blocker is stuck and requires intervention
- `"needs_attention"` – blocker demands immediate human action

### Key Diagnostic Fields

The [`IssueBlockerAttention`](https://github.com/paperclipai/paperclip/blob/master/packages/shared/src/types/issue.ts#L399-L414) interface (lines 399–414) carries:

| Field | Purpose |
|-------|---------|
| `reason` | Why the blocker exists (e.g., `"active_dependency"`) |
| `terminalBlockerIssueId` | The leaf blocker requiring human action |
| `blockingTreeLive` | Boolean indicating whether any descendant is already running |

These fields enable both the UI and server to make precise decisions about when and how to surface blocker-related actions.

## Topological Sorting: The workflowSort Algorithm

The UI must present issues in an order that preserves dependency chains. The [[`ui/src/lib/workflowSort.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/lib/workflowSort.ts)](https://github.com/paperclipai/paperclip/blob/master/ui/src/lib/workflow-sort.ts) utility implements a **chain-aware topological sort** that keeps linear blocker sequences contiguous.

### Core Algorithm Structure

The `workflowSort` function builds two auxiliary structures:

```typescript
// From workflowSort.ts lines 90–104
const successors = new Map<string, string[]>();  // issueId → array of blockers
const inDegree = new Map<string, number>();      // count of incoming blocker edges

```

It then performs a **chain walk**: starting from each root, it follows the `successors` map as long as exactly one successor exists. This produces contiguous chains for the common case of `A ← B ← C` dependencies.

### Fallback Behaviors

The algorithm includes defensive measures for edge cases:

1. **Cross-parent blockers** – When a chain branches (more than one successor or predecessor), the walk breaks and ordering falls back to timestamp/id tie-break (see the `if (succIds.length !== 1) break;` guard).

2. **Missing blockers** – Issues referencing non-existent blockers still display the blocker chip but receive no special ordering treatment (comment lines 14–15).

3. **Cycle detection** – If the output size doesn't match input size after sorting, the function degrades to a pure timestamp/id sort (lines 106–108), preventing infinite loops when the API's acyclicity validation fails.

The overall complexity is **O(N + E)** time, suitable for large boards.

## Attention Generation: From Blocker State to Action

The server-side [[`attention.ts`](https://github.com/paperclipai/paperclip/blob/main/attention.ts)](https://github.com/paperclipai/paperclip/blob/master/server/src/services/attention.ts) service bridges blocker diagnostics and user-facing actions. Located in [[`server/src/services/attention.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/services/attention.ts)](https://github.com/paperclipai/paperclip/blob/master/server/src/services/attention.ts#L1444-L1526), it queries blocked issues and produces **attention items**—structured recommendations for the UI.

### Query and Candidate Selection

Lines 44–82 fetch all issues with `status: "blocked"`. For each, the service examines `blockerAttention.state` to determine severity.

### Terminal Blocker Handling

Lines 108–154 implement the critical logic for **stalled or needs-attention blockers**:

```typescript
// Simplified from attention.ts lines 108–154 and 322–355
if (blockerAttention?.state === "stalled" && !blockerAttention.blockingTreeLive) {
  add(createItem({
    sourceKind: "blocker_attention",
    subject: issueSubject(prefix, terminalSummary),
    whyNow: `Blocks ${blockedTaskCount} tasks and needs human attention.`,
    decisionVerbs: decisionVerbs(
      { id: "unblock", label: "Unblock", description: "Repair the blocker" },
      { id: "reassign", label: "Reassign", description: "Assign to a live owner" },
      { id: "nudge", label: "Nudge", description: "Prompt the current owner" }
    ),
    severity: "high"
  }));
}

```

The `terminalBlockerIssueId` field ensures users act on the **actual leaf blocker** rather than intermediate nodes in a dependency chain.

## Execution Semantics Summary Table

| Situation | System Behavior | Implementation Location |
|-----------|---------------|------------------------|
| Issue A blocked by B | A cannot exit `"blocked"` status until B resolves | `blockedBy` field + `issuesSvc.update` |
| Linear chain A←B←C | UI renders A → B → C contiguously | [`workflowSort.ts`](https://github.com/paperclipai/paperclip/blob/main/workflowSort.ts) lines 90–104 |
| Cross-parent blocker | Chain walk breaks; timestamp fallback | [`workflowSort.ts`](https://github.com/paperclipai/paperclip/blob/main/workflowSort.ts) successor guard |
| Stalled blocker | High-severity attention item with `Unblock`/`Reassign`/`Nudge` verbs | [`attention.ts`](https://github.com/paperclipai/paperclip/blob/main/attention.ts) lines 108–154 |
| Missing blocker reference | Blocker chip displays; no ordering special case | [`workflowSort.ts`](https://github.com/paperclipai/paperclip/blob/main/workflowSort.ts) comment lines 14–15 |
| Cycle in dependencies | Degrade to timestamp/id sort | [`workflowSort.ts`](https://github.com/paperclipai/paperclip/blob/main/workflowSort.ts) lines 6–8, 106–108 |

## Practical Code Examples

### Creating a Blocker Relationship

```typescript
// Client → server: establish dependency
await issuesService.update(issueId, {
  status: "blocked",
  blockedByIssueIds: [blockerId]  // Must belong to same company
});

```

### Sorting Issues with Blocker Awareness

```typescript
import { workflowSort } from "@/lib/workflowSort";

const sorted = workflowSort(issues);  // Issue[] from API
// Preserves linear chains, falls back to creation time otherwise

```

### Generating Attention Items Server-Side

The attention service pattern shows how to surface actionable intelligence from blocker state—checking `blockerAttention.state`, validating `!blockingTreeLive`, and constructing decision verbs for the UI.

## Key Implementation Files

| File | Path | Responsibility |
|------|------|--------------|
| **Shared Types** | [[`packages/shared/src/types/issue.ts`](https://github.com/paperclipai/paperclip/blob/main/packages/shared/src/types/issue.ts)](https://github.com/paperclipai/paperclip/blob/master/packages/shared/src/types/issue.ts) | `Issue`, `IssueBlockerAttention`, state enums |
| **Workflow Sort** | [[`ui/src/lib/workflowSort.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/lib/workflowSort.ts)](https://github.com/paperclipai/paperclip/blob/master/ui/src/lib/workflow-sort.ts) | Topological + chain-aware ordering |
| **Attention Service** | [[`server/src/services/attention.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/services/attention.ts)](https://github.com/paperclipai/paperclip/blob/master/server/src/services/attention.ts) | Item generation for stalled blockers |
| **Issue Service** | [[`server/src/services/issues.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/services/issues.ts)](https://github.com/paperclipai/paperclip/blob/master/server/src/services/issues.ts) | API for `blockedByIssueIds` updates |
| **UI Blocker Chip** | [[`ui/src/lib/blockedInbox.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/lib/blockedInbox.ts)](https://github.com/paperclipai/paperclip/blob/master/ui/src/lib/blockedInbox.ts) | Blocker metadata rendering |
| **Pipeline Types** | [[`ui/src/api/pipelines.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/api/pipelines.ts)](https://github.com/paperclipai/paperclip/blob/master/ui/src/api/pipelines.ts#L177) | Blocker exposure to pipeline views |

## Summary

- **Safety**: The `blockedBy` field enforces hard dependencies—no issue advances while blockers remain unresolved.
- **Predictability**: `workflowSort` maintains contiguous blocker chains so users perceive dependency structure clearly.
- **Actionability**: The `attention` service transforms `stalled`/`needs_attention` states into specific UI verbs (`Unblock`, `Reassign`, `Nudge`).
- **Resilience**: Edge cases (missing blockers, cycles, cross-parent dependencies) degrade gracefully without system failure.

These semantics operate across the full stack—from type definitions in `packages/shared` through UI ordering in `ui/src/lib` to server intelligence in `server/src/services`.

## Frequently Asked Questions

### How does Paperclip prevent circular dependencies between issues?

The API layer validates acyclicity before persisting `blockedByIssueIds`. As a defensive measure, `workflowSort` detects size mismatches post-sort (lines 106–108) and falls back to timestamp-based ordering if cycles somehow reach the client.

### What happens when a blocker issue is deleted?

The `blockedBy` reference persists but becomes a **phantom blocker**. The UI still renders the blocker chip (per [`workflowSort.ts`](https://github.com/paperclipai/paperclip/blob/main/workflowSort.ts) comment lines 14–15), but the sorting algorithm treats it as absent—no special chain positioning applies.

### Can multiple issues block a single dependent issue?

Yes. However, `workflowSort` only produces contiguous chains for **linear dependencies** (single successor, single predecessor). When an issue has multiple blockers, the chain walk breaks and ordering falls back to timestamp/id tie-break.

### What triggers a "needs_attention" blocker state?

The `attention` service (lines 44–82) identifies blockers where human intervention is required—typically when `blockingTreeLive` is false and diagnostics indicate the blocker is not being actively addressed. This generates high-severity attention items with specific resolution verbs.