Docs/Projects/The ticket DAG
// PROJECTS

The ticket DAG

The tickets a projectgenerates aren't a flat to-do list — they form a dependency graph. Some tickets can't start until others finish. Leroy tracks those relationships, works whatever is unblocked, and integrates the results on a shared branch as the project takes shape.

01 Tickets as a graph

A project's tickets are a DAG— a directed acyclic graph. "Directed" because dependencies point one way (A must finish before B starts); "acyclic" because nothing can end up waiting on itself. In practice that just means the work has an order: some tickets are foundations, others build on top of them.

A
Add the migration & schema
No dependencies — ready to start now. Foundational work the others build on.
B
Build the API endpoints
Blocked by A — needs the schema in place before it can start.
C
Wire up the UI
Blocked by B — needs the endpoints to call.

Illustrative only — a real project's graph can branch and merge, with several tickets unblocked at once.

02 Blockers

A blocker is a dependency edge: ticket B is blocked by ticket A when A has to land first. A ticket can have several blockers, and it stays blocked until all of them clear. Tickets with no remaining blockers are ready.

State
Meaning
ready
No open blockers — Leroy can start it.
blocked
Waiting on one or more upstream tickets to finish first.

03 How Leroy schedules

Leroy walks the graph rather than the list. It works the tickets that are ready, and the moment a ticket lands, any ticket that was blocked only by it becomes ready and gets picked up next. Independent branches of the graph can move in parallel.

  1. Start with the roots. Tickets that have no blockers are eligible immediately.
  2. A blocker clears. When a ticket finishes, Leroy re-checks everything that depended on it.
  3. Newly-ready tickets move. Any ticket whose last blocker just cleared becomes ready and gets scheduled.
  4. Repeat until the graph drains. The project completes when every ticket has landed.
i
Policy gates still apply per ticket. Being unblocked means a ticket can be worked — it still passes the intake, plan, and ship gates like any other ticket, so an Always-ask gate will still pause it for you.

04 The shared branch

A project's tickets converge on a shared integration branch instead of merging straight to your default branch one at a time. As each ticket ships, its work integrates there, so downstream tickets build on top of the real, combined state — not on a stale base. The project lands as a coherent whole rather than a scatter of independent merges.

Which branch a given ticket builds on follows the base-branch precedence described in the Projects overview: the ticket's own base branch, then the project's, then the repo default.