Insight

The Roadmap and the Codebase Are Different Trees

One tracking tree for intent, structure, and work feels like traceability. It is three trees forced into one parent chain, and it reorganizes every time the roadmap does.

Alaa Almallah 9 min read

A team designs the tracker to end all trackers. Platform at the root. Jobs to be done under it, then journey stages, then features, then services, modules, functions, and tasks at the leaves. Eight levels of GitHub sub-issues. A treemap for functionality progress, a story map for flows, both projected from the same tree. In week one it is beautiful. Every function traces up to a job to be done. Every status rolls down to a number.

Then the roadmap moves. A quarterly review retires one of the jobs to be done. The subtree underneath does not retire with it. Those services and modules are still in production, still load-bearing. They get re-filed in an afternoon under whichever feature sits closest. Search is re-parented three times in two months, because it serves every flow and belongs to none.

Nobody did anything wrong. The tree asked a question that has one answer. The truth had three.

Three trees wearing one trunk

What got fused into that chain were three different trees:

TreeOrganizesChanges withTypical levels
Intentwhy the work existsroadmap decisionsoutcome, flow, capability
Structurehow the system is builtrefactorsservice, module, function
Workeffort over timedaily executionepic, task

Different lifespans. Different parent semantics. And many-to-many between them: one service serves many flows, one flow touches many services. Fusing them into one parent chain fails in two ways.

First, the single-parent problem. A sub-issue in GitHub has exactly one parent, and nesting runs eight levels deep. A service that serves every flow must choose a primary one, and at that choice the traceability the design was built for dies silently for every other flow. The alternative is duplicating the node under each flow, which ends the single source of truth the design was also built for.

Second, the stability inversion. Durable structure ends up parented under transient intent. Code outlives roadmaps, but the filing pretends otherwise, so intent churn corrupts structure.

That second failure deserves its own name, because it is the one that guarantees the outcome: a tracking hierarchy rots at the rate of its most volatile layer. Rot here is not decay from neglect. It is churn inherited from an ancestor. Parent services under a quarterly roadmap and the entire tree reorganizes quarterly, no matter how carefully anyone files.

This is the tracking cousin of What the Spec Doesn't Decide, the Model Will. There, every gap in a spec became a decision the model took silently. Here, every many-to-many the tree cannot hold becomes a parentage decision the filing takes silently. The tool's shape decides, and nobody notices the decisions being made.

Why does the rolled-up percentage lie?

The single tree exists to produce one number, so it blends everything into one number. Two things break.

The weights are fiction. Roll-up needs a weight, and every candidate distorts under pressure. Lines of code reward bloat and punish the refactor that deletes code. Ticket count rewards splitting one task into five. Estimates are optimistic fiction by week three, and everyone knows it, which is why nobody defends the number when it is questioned.

The denominators do not match. The top of the tree is outcomes. Everything under it is output. You can close one hundred percent of the tasks and not move the outcome, either because the decomposition was wrong or because the tasks that mattered were never on the tree at all. The blended percentage is neither a work figure nor an outcome figure. Worse, it hides the single most diagnostic signal available, which is the gap between work done and outcome moved.

This is Automation Does Not Remove Judgment. It Reassigns It in a spreadsheet. The roll-up does not remove the judgment about what matters. It buries that judgment in a weight nobody reads again, then presents the output as a fact. It is also Most Technical Debt Is Deferred Judgment, Not Bad Code at the tracker level: the weight is a deferred decision wearing a formula's confidence.

A stale tree is worse than a flat board

Depth is ceremony. Every pull request has to land on the right leaf task, and five or more intermediate ancestors have to stay correct, and the humans doing that filing stop bothering around week three, because the filing was never the job.

What is left is worse than a flat board, not equal to one. A flat board that is current tells the truth poorly. A deep tree that is wrong tells a lie fluently, because it has structure, and structure reads as maintained, and maintained reads as true. Workflow Theater vs Workflow Gain names the general pattern: the tracker demos traceability while the team quietly re-derives the real structure in their heads, where it has always lived.

What this is not

Not a case against hierarchy. Two shallow trees are still hierarchy. The move is not to flatten, it is to stop fusing.

Not a case against traceability. Mapping fields carry many-to-many traceability, which the single chain could never hold in the first place. One task tagged service:search and flow:checkout traces to both, honestly, forever.

And not a tool complaint. GitHub supports this shape today. The flaw was never the tool. It was the shape the tool was asked to enforce.

The move: two trees and a label

The repair keeps what the original design wanted and removes what guarantees the rot.

  1. Keep the intent tree shallow: outcome, flow stage, capability. Three levels, changing with the roadmap, dying with the roadmap.
  2. Derive the structure tree from the repository. Services and modules exist in code. A tracker that re-types them by hand is a second copy waiting to disagree.
  3. Keep the work tree nearly flat: epic, task. Put jtbd, flow, and service on each task as fields. The fields are the projection layer. They give the treemap and the story map everything the eight-level chain gave, without the single-parent lie.
  4. Roll up work progress inside the work tree only. Give each outcome its own metric, plotted beside the work bar, never blended into it. The gap between those two lines is the status.
  5. Earn depth. Add a level only after a question you actually asked cannot be answered flat. Depth that is designed in ahead of demand is ceremony waiting for its excuse.

The uncomfortable version of the whole argument: a single unified tree feels like alignment. It is actually a bet that the roadmap will stop moving. No team makes that bet on purpose. They make it by accepting the default parent chain the tool offers.

Take-home

  • Find the node in your tracker whose parent changes whenever the roadmap changes. That node is fused. Split it this week.
  • If tasks carry their service or module ancestry by hand, move it to a field. The filing stops, the traceability stays.
  • Put one outcome metric beside its work roll-up on the same dashboard. If the two lines disagree, the disagreement is the real status report.
  • If a hierarchy has already rotted, do not re-file it. Archive the tree, restart shallow, and keep the fields.

Related reading:

If your tracker reorganizes every time the roadmap does, the problem is not filing discipline. It is the shape of the tree. If you want help splitting intent, structure, and work before more process builds on the fusion, book a discovery call.

FAQ

Why can't one hierarchy serve both the roadmap and the codebase?

Because they are different trees with different lifespans and a many-to-many relation between them. The roadmap is an intent tree that changes quarterly. The codebase is a structure tree that changes with refactors. Fusing them into one parent chain forces shared services to pick a single parent flow and parents durable code under transient intent, so the whole tree inherits the roadmap's churn rate.

What is tree rot in a tracking system?

A tracking hierarchy rots at the rate of its most volatile layer. Rot is not decay from neglect. It is churn inherited from an ancestor. When services are filed under quarterly roadmap items, the tree reorganizes every quarter regardless of how carefully anyone maintains the filing.

Why do progress roll-ups mislead teams?

Two reasons. The weights distort under pressure: lines of code reward bloat, ticket counts reward splitting, estimates drift into fiction. And the denominators do not match: the top of the tree measures outcomes while everything below measures output, so you can finish one hundred percent of the tasks without moving the outcome, and the blended number hides that gap.

How do you keep traceability without a single tree?

Use two shallow trees plus mapping fields. Keep outcome, flow, and capability as one tree, services and modules as another, and epic and task as the work layer. Put jtbd, flow, and service fields on each task. The fields carry many-to-many traceability that a single parent chain can never represent.

How deep should a work hierarchy go?

Start at two levels, epic and task, with services and flows as fields rather than ancestors. Add a level only when a question you actually asked cannot be answered flat. Depth designed in ahead of demand is ceremony, and ceremony stops being maintained around week three, which leaves a stale tree that reads as more trustworthy than a flat board while being less honest.

Related