Mert Özen Further With Every Line
Project Management Kanban — #06

Actively Managing Flow in Kanban: Blockers, Aging and Flow Reviews

Mert Özen Nov 8, 2026 12 min 1 views
Actively Managing Flow in Kanban: Blockers, Aging and Flow Reviews

Actively managing flow means reading the board right to left from the oldest item every day, escalating blocked work, limiting expedite and finding the bottleneck with data. We compute CFD band widths from Bookstore data in C#, see how Code Review became the bottleneck in July, how the Theory of Constraints steps solved it (p85 from 16 to 11 days), and why the next constraint is the deploy rhythm.

Version note: This post is based on version 2025.5 of The Kanban Guide; Kanban University sources were consulted for the Kanban Method cadences. The analysis code was run with .NET 10 on the Bookstore board data from post 04.

Guess First

July 2026, the Bookstore team. On average six PRs (pull requests) are waiting in the Code Review column, some of them for a week. The developers complain: "I'm waiting for a review, so I picked up something new." The tester complains: "Nothing reaches me, then on Thursday five items land at once." The product owner complains: "Even a small bug takes two weeks."

The team has three options. One, hire another senior developer to speed up reviews. Two, set a rule that "every developer reviews at least two PRs a day." Three, put a tight WIP (Work in Progress) limit on the In Dev column and add a limit to Code Review too, which slows down developers starting new work. Which one shortens cycle time the most? And consider this: once Code Review is solved, where will the next wait show up?

The Daily Flow Meeting: Right to Left, Oldest First

The Kanban Guide doesn't define a specific meeting; it asks for active items to be reviewed regularly and says this can be done continuously, at intervals or both. Most teams do it with a 15-minute board meeting every morning. If you're a Scrum team, this is your Daily Scrum; as the Scrum series' Daily Scrum post explains, that meeting is already a planning event, not a status report.

A flow-focused daily meeting has two rules. First, read the board from right to left: Ready to Deploy first, then Test, Code Review, and In Dev last. The work on the right is closest to done; finishing it produces more value than moving a new item on the left. Second, start with the oldest item: the topmost dot on the aging chart from post 04 is the first item on the agenda.

The questions asked in this meeting are about the work, not the people:

  • Which item is closest to done, and what does it take to finish it today?
  • Is any item approaching or past the SLE (Service Level Expectation)? Who can help move it forward?
  • Is anything blocked? Who will remove the obstacle, and by when?
  • Is any column's WIP limit full? If so, who will help that column instead of pulling new work?
  • Is anyone doing work that isn't on the board?

"What did you do yesterday, what will you do today?" makes every person look busy but moves no item. "How do we move our oldest item forward today?" gathers the team around the work.

Blocked Items: Label, Reason, Duration

The Kanban Guide includes unblocking stuck work in its active management practice. The Bookstore policy in post 02 was simple: a blocked item stays in its column, gets a label and a reason, and keeps counting toward WIP. Add two habits on top of that.

First, measure blocked time. That's why Bookstore's CSV (Comma-Separated Values) has a BlockedDays column. Adding up how many days each reason blocked work over six months shows which external dependency the team gets stuck on most often. At Bookstore the most familiar example is the payment provider's test environment.

Second, set an escalation threshold. BS-1205 was blocked for 12 days waiting on the payment provider's test environment and, at 19 days old, is well past the SLE. The team could have done two things for this item: take it to the team lead and to whoever manages the relationship with the provider on the third day of the blocked label, or split the item and ship the part that doesn't depend on the provider (the fallback screen, the logging) as a separate item. The worst thing to do while a blocked item waits is to quietly start new work in its place.

The Expedite Policy and Its Cost

On a support-heavy team some work doesn't wait in line: "card payments are failing at checkout," for instance. The Kanban Method uses the idea of classes of service for this kind of work; the best-known classes are expedite, fixed date, standard and intangible. Expedite is the class where the work jumps ahead of everything else.

Expedite has a cost: every hour spent on that item means the other items on the board wait. That's why the Bookstore policy limited the expedite lane to a single item at a time and counted it in total WIP. But the data revealed something interesting. The last section of the code below lists the cycle times of items whose title starts with "Urgent": 10 items, between 6 and 14 days. So expedite only meant jumping to the front of Ready; afterwards the item waited in the Code Review queue like everything else, and then for the Tuesday or Thursday deploy. Once the team saw this, it changed the expedite policy: an expedite item is reviewed the same day and, if needed, ships as a hotfix without waiting for deploy day. Having the policy written down is what made it possible to measure and fix it.

Finding the Bottleneck: Computing the CFD

In post 04 we said the bands of a CFD (Cumulative Flow Diagram) show the number of items in each state. We can compute the same information without drawing the chart: counting how many items sit in each state on each day and averaging per month is the numeric form of the band widths in a CFD. The FlowReview project, using the WorkItem types from post 04:

using System.Globalization;
using Bookstore.Flow;

CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;

List<WorkItem> items = BoardCsv.Load("board-history.csv");
string[] active = ["InDev", "CodeReview", "Test", "ReadyToDeploy"];

// One day's slice of the CFD: how many items sit in each state that day?
int InState(string state, DateOnly day) => items.Count(i =>
{
    if (!i.Entered.TryGetValue(state, out DateOnly entered) || entered > day)
        return false;
    int next = BoardCsv.States.IndexOf(state) + 1;
    return !i.Entered.TryGetValue(BoardCsv.States[next], out DateOnly left) || left > day;
});

Console.WriteLine("Month    | avg items per state (CFD band width)              | median days in CodeReview");
Console.WriteLine("         | InDev  CodeReview  Test  ReadyToDeploy  total WIP |");
for (int month = 5; month <= 10; month++)
{
    DateOnly first = new(2026, month, 1);
    DateOnly[] days = [.. Enumerable.Range(0, DateTime.DaysInMonth(2026, month)).Select(d => first.AddDays(d))];
    double[] bands = [.. active.Select(s => days.Average(d => InState(s, d)))];

    List<int> reviewDays = [.. items
        .Where(i => i.Entered.TryGetValue("Test", out DateOnly t) && t.Month == month)
        .Select(i => i.Entered["Test"].DayNumber - i.Entered["CodeReview"].DayNumber)
        .Order()];

    Console.WriteLine($"{first:yyyy-MM}  | {bands[0],5:F1}  {bands[1],10:F1}  {bands[2],4:F1}  {bands[3],13:F1}  {bands.Sum(),9:F1} | " +
        $"{reviewDays[reviewDays.Count / 2],3} d (n = {reviewDays.Count})");
}

// Effect of the change: two periods by start date
Console.WriteLine();
Console.WriteLine("Started            | finished n | cycle time p50 / p85 | median days in CodeReview / ReadyToDeploy");
PrintPeriod("Jun 1 - Aug 31", new(2026, 6, 1), new(2026, 8, 31));
PrintPeriod("Sep 7 - Oct 30", new(2026, 9, 7), new(2026, 10, 30));

// Did expedited work really move faster?
List<int> urgent = [.. items.Where(i => i.Title.StartsWith("Urgent") && i.Finished is not null)
    .Select(i => i.CycleTimeDays!.Value).Order()];
Console.WriteLine();
Console.WriteLine($"Urgent items: n = {urgent.Count}, cycle times = [{string.Join(", ", urgent)}] d");

void PrintPeriod(string label, DateOnly from, DateOnly to)
{
    List<WorkItem> done = [.. items.Where(i => i.Started >= from && i.Started <= to && i.Finished is not null)];
    List<int> ct = [.. done.Select(i => i.CycleTimeDays!.Value).Order()];
    int Median(string state, string next) => done
        .Select(i => i.Entered[next].DayNumber - i.Entered[state].DayNumber)
        .Order().ElementAt(done.Count / 2);

    Console.WriteLine($"{label,-18} | {done.Count,10} | {Stats.Percentile(ct, 50),8} / {Stats.Percentile(ct, 85),2} d    | " +
        $"{Median("CodeReview", "Test"),5} d / {Median("ReadyToDeploy", "Done")} d");
}

The real output:

Month    | avg items per state (CFD band width)              | median days in CodeReview
         | InDev  CodeReview  Test  ReadyToDeploy  total WIP |
2026-05  |   3.0         2.6   1.3            1.5        8.4 |   3 d (n = 23)
2026-06  |   4.5         4.2   1.6            3.3       13.6 |   4 d (n = 35)
2026-07  |   2.9         5.8   1.8            2.8       13.4 |   5 d (n = 39)
2026-08  |   3.1         4.8   1.4            3.2       12.5 |   5 d (n = 30)
2026-09  |   3.4         2.4   1.8            2.9       10.6 |   1 d (n = 37)
2026-10  |   3.8         1.6   1.8            2.4        9.5 |   1 d (n = 34)

Started            | finished n | cycle time p50 / p85 | median days in CodeReview / ReadyToDeploy
Jun 1 - Aug 31     |        105 |       12 / 16 d    |     5 d / 2 d
Sep 7 - Oct 30     |         51 |        8 / 11 d    |     1 d / 2 d

Urgent items: n = 10, cycle times = [6, 6, 7, 8, 8, 9, 9, 9, 13, 14] d

The first part of the table tells the story. The Code Review band thickens from an average of 2.6 items in May to 5.8 in July, and the median time a PR spends in Code Review rises from 3 to 5 days. In the same period the In Dev band does not thin out; developers start new work while waiting for reviews and total WIP climbs from 8.4 to 13.6. This is the real-life counterpart of the simulation in post 03: WIP grows while throughput stays the same, and Little's Law forces cycle time up.

A Short Introduction to the Theory of Constraints

The core idea of the Theory of Constraints, popularized by Eliyahu Goldratt's 1984 novel "The Goal," is this: a single bottleneck in a system, the constraint, determines the system's output. Speeding up a step other than the constraint doesn't speed up the system; it only grows the queue in front of the constraint. Goldratt proposes a five-step process for this: identify the constraint, exploit it fully, subordinate everything else to it, elevate its capacity if needed, and start over when the constraint moves.

In September the Bookstore team applied these steps almost word for word. It identified the constraint: the band thickening in the CFD was Code Review. It exploited it: the policy "review a waiting PR before starting new work" turned Code Review from a spare-time chore into the first thing developers do. It subordinated everything else to it: it set WIP limits of 5 on In Dev and 3 on Code Review; when Code Review is full, nobody starts new work. It elevated its capacity: it moved to pairing on big features, so code written by two people has already had a first review before it ever enters the queue. It did not hire another senior developer.

Back to the three options at the start: hiring someone would add capacity to the constraint but take months, and without limiting WIP the new person would also start new work. The "two reviews a day" rule sets a target but doesn't put reviewing before starting new work. The third option, WIP limits, feeds the constraint directly: a limit on In Dev redirects a developer's idle time to Code Review.

The second part of the table shows the result. The 105 items started between June and August have a p50 cycle time of 12 days and a p85 of 16; the 51 items started after 7 September have 8 and 11 days. The median time in Code Review dropped from 5 days to 1. One caveat: the second period is shorter, and items that started in late October and haven't finished yet are not in the calculation, which makes the number look slightly optimistic. Still, the difference is far bigger than that bias can explain.

The fifth step is starting over. With Code Review solved, the next constraint became visible: the Ready to Deploy band is still 2.4–2.9 items in September–October, and an item waits there a median of 2 days. That wait is a direct consequence of deploying twice a week. The team's next improvement is not a board rule but an engineering investment: making it possible to deploy every day. How to do that is the subject of the CI/CD Fundamentals series, which covers CI (Continuous Integration) and CD (Continuous Delivery), and of the Deployment Strategies series.

In post 02 we asked when it makes sense to split the Code Review column into "Waiting for Review" and "In Review." The answer is in this analysis: when waiting and working need to be measured separately. Had you split the column in June, you would have seen directly that the band was thickening not because reviews took long but because they didn't start. After September, with the median down to 1 day, the payoff of splitting shrank; the team kept a single column.

Replenishment and Kanban Method Cadences

Active management also has rhythms outside the board. Replenishment is the decision of when and with what the Ready column is refilled. The Bookstore team does it every Monday in a 20-minute meeting with the product owner and caps Ready at 8 items; Ready is itself a queue, so if it is left unlimited the work waiting there goes stale and priorities get outdated.

The Kanban Method describes these rhythms in more detail under the name cadences. The set that spread around Anderson's work has seven cadences: the daily Kanban meeting, the Replenishment meeting, the Delivery Planning meeting, the Service Delivery Review, the Operations Review, the Risk Review and the Strategy Review. Of these, the Service Delivery Review suits a team especially well: every few weeks, together with the customer side, discuss how well the team meets its SLE, its flow metrics and the requests waiting.

The Kanban Guide makes none of these meetings mandatory. Version 2025.5 asks for the DoW (Definition of Workflow) to be reviewed from time to time and says there's no need to wait for a formal, recurring meeting to do so. So according to the Guide, improvement is the job of a continuous practice, not of a meeting; cadences are one way of embedding that practice in an organization.

In Production

Record changes with dates. The Bookstore team changed its WIP limits on 7 September and knows that date; that's how it could split the analysis into two periods around it. Writing a one-line note for every change to the board, the DoW or the team lets you answer "why did it improve?" a few months later.

Change one variable at a time. In September the team changed WIP limits, review priority and pairing all at once; the result is good, but we can't separate from this data how much each one contributed. When improvements are small and sequential, their effects can be read separately.

Keep the celebration short once the bottleneck is solved. The constraint moves; at Bookstore it moved from Code Review to the deploy rhythm. Stopping the search for the next bottleneck is the shortest path to the system slowing down again.

Common Pitfalls

The first pitfall is leaving improvement to the retro alone. A retro every two weeks is far too late to notice six PRs piling up in Code Review. The Guide's improvement practice says not to wait for a formal meeting; asking "this column has been full for three days, should we change our policy?" at the daily meeting is improvement too.

The second is using metrics to evaluate people. A ranking of "the developer who finished the most items" or "the developer with the lowest cycle time" pushes people to finish their own work instead of reviewing someone else's PR; it recreates exactly the bottleneck we solved in this post. Flow metrics measure the health of the system.

The third is making expedite common. If half a dozen "urgent" items arrive every week, most of them aren't urgent, just requested loudly. Write in the policy whose approval a new urgent item needs to enter when the expedite limit is full.

The fourth is speeding up the wrong place. Had the team added a developer in June, more work would have started and the Code Review queue would have grown even larger. Capacity added outside the constraint feeds the queue in front of the constraint.

A Small Experiment

★☆☆ Run tomorrow morning's meeting on your own board from right to left, starting with the oldest item. How much did the meeting's length and the topics discussed change?

★★☆ The data doesn't split Code Review into waiting and working. Add to the FlowReview program the monthly share of items that stayed in Code Review longer than 1 working day. How well did the team keep the "at most 1 working day" policy from post 02 after September?

★★★ Treat expedite items as a separate DoW: give them their own started/finished points and their own SLE. Compute an SLE from the "Urgent" items in the Bookstore data and write down which policies would have to change to reach the target "85% of expedite items in production within 2 days."

Throughout the series we've described Kanban through a team separate from Scrum. In the last post we bring the two together: Corey Ladas's Scrumban, how the Kanban Guide for Scrum Teams adds flow metrics to the Sprint events, and which choice makes sense for which team.