Module 7: Strategy To Roadmap

From strategy to bets

Description

A well-written strategy —"we win with curated discovery and seller trust, not the lowest price"— doesn't, on its own, tell anyone what to build next quarter. Between the strategy's sentence and the line of code there's an intermediate step almost no team makes explicit: turning that sentence into a set of bets —concrete candidates to build, each carrying an implicit or explicit claim about which part of the strategy it serves. This lesson teaches you to take that step with discipline, not by eyeballing it.

Connection to the module. Module 1 opened with the complete map: filter before RICE. This lesson builds the first half of the machinery that makes that filter possible — the label, servesDimensions, that turns a vague idea ("we should improve checkout") into a verifiable claim ("this bet serves the convenience dimension"). Without that label, there's nothing for the filter to evaluate. Lesson 3 takes that label and builds the complete filter.

An everyday analogy: the architect and the materials list

An architect delivers a blueprint with a sentence of intent written on the first page: "this house wins with abundant natural light and open spaces that flow into each other." That sentence, alone, is useless to the foreman at seven o'clock Monday morning — it doesn't tell them which brick to buy, which window to order, or whether the back wall comes down or stays. Before construction can start, someone has to translate that intent into a concrete materials list: large windows on the north and south facades (serves "natural light"), no central columns in the main living room (serves "open spaces"), and —this is the uncomfortable part— not an extra basement room with one small window, no matter how much the client asks for it or how cheap it would be, because that line item doesn't serve either of the blueprint's two intentions.

Every line of that materials list is a bet: a concrete decision claiming to serve a specific intent from the blueprint. A materials list without that traceability —without every line able to point to which intent of the blueprint it responds to— isn't a materials list for this house; it's a materials list for any house, chosen out of habit or convenience. That's exactly what happens to a roadmap when its bets don't carry the label of which part of the strategy they claim to serve.

Worked example: three bets, the same label that makes them comparable

We take three candidates from Mercado's backlog and assign each the strategic dimension it claims to serveservesDimensions— before asking whether that claim holds up against the real strategy. It's, deliberately, the same translation mechanism the foreman used with the materials list: naming, for each bet, which part of the blueprint it says it addresses.

function riceScore({ reach, impact, confidence, effort }) {
  return (reach * impact * confidence) / effort;
}

// Pedagogical model: a bet "belongs to the strategy" if at least one of the
// dimensions it serves is in strategy.winOn (what the strategy chose to WIN
// on, modules 3-4) AND none is in strategy.avoid (what the strategy
// explicitly chose NOT to fight on, module 2/5). Serving a neutral
// dimension (neither winOn nor avoid) isn't enough to belong: strategic
// coherence requires REINFORCING the chosen game, not just not getting in its way.
function strategicFilter(backlog, strategy) {
  return backlog.map((bet) => {
    const reinforces = bet.servesDimensions.filter((d) => strategy.winOn.includes(d));
    const conflicts = bet.servesDimensions.filter((d) => strategy.avoid.includes(d));
    return {
      feature: bet.feature,
      servesDimensions: bet.servesDimensions,
      reinforces,
      conflicts,
      inStrategy: reinforces.length > 0 && conflicts.length === 0,
      riceScore: Number(riceScore(bet.rice).toFixed(2)),
    };
  });
}

const mercadoStrategy = { winOn: ['curatedDiscovery', 'sellerTrust'], avoid: ['price'] };

// Three candidate bets, each labeled with the strategic dimension it
// CLAIMS to serve -- that label is the very translation of "bet".
const candidateBets = [
  { feature: 'sellerTools', servesDimensions: ['sellerTrust'], rice: { reach: 1200, impact: 2, confidence: 0.8, effort: 2 } },
  { feature: 'recommendations', servesDimensions: ['curatedDiscovery'], rice: { reach: 5000, impact: 1, confidence: 0.5, effort: 3 } },
  { feature: 'lowestPriceMatch', servesDimensions: ['price'], rice: { reach: 9500, impact: 3, confidence: 0.8, effort: 3 } },
];

console.log('=== From strategy to bets: which dimension does each one claim to serve ===\n');
console.table(strategicFilter(candidateBets, mercadoStrategy));

What to expect. Running the file with Node produces exactly this output:

=== From strategy to bets: which dimension does each one claim to serve ===

┌─────────┬────────────────────┬────────────────────────┬────────────────────────┬─────────────┬────────────┬───────────┐
│ (index) │      feature       │    servesDimensions    │       reinforces       │  conflicts  │ inStrategy │ riceScore │
├─────────┼────────────────────┼────────────────────────┼────────────────────────┼─────────────┼────────────┼───────────┤
│    0    │   'sellerTools'    │   [ 'sellerTrust' ]    │   [ 'sellerTrust' ]    │     []      │    true    │    960    │
│    1    │ 'recommendations'  │ [ 'curatedDiscovery' ] │ [ 'curatedDiscovery' ] │     []      │    true    │  833.33   │
│    2    │ 'lowestPriceMatch' │      [ 'price' ]       │           []           │ [ 'price' ] │   false    │   7600    │
└─────────┴────────────────────┴────────────────────────┴────────────────────────┴─────────────┴────────────┴───────────┘

Notice something that's going to repeat throughout the module: the servesDimensions column isn't an opinion, it's a verifiable claim. sellerTools claims to serve sellerTrust, and that claim can be debated in a product meeting ("does a seller tool really build buyer trust, or does it just make sellers' lives easier?") — but, once the team agrees on it, it's written down, not floating in whoever proposed it's head. lowestPriceMatch claims to serve price, and that claim is also clear and honest: nobody's pretending that matching prices serves curated discovery. The honesty of the label is precisely what makes it possible for lesson 3's filter to evaluate it without ambiguity.

Deep dive: the label isn't the filter, it's its input

A common confusion at this early stage: thinking that just writing servesDimensions already "does" the strategic work. It doesn't — the table above still shows each bet's riceScore, and still calculates inStrategy, because the complete model (strategicFilter, built out in full in lesson 3) is already running underneath. What this lesson isolates is the earlier step, the one almost nobody makes explicit: deciding, honestly, which dimension of the strategy each candidate claims to serve, before looking at whether that claim holds up.

That step has an easy trap to fall into: labeling a bet with the dimension one wishes it served, not the one it actually serves. It's tempting to label lowestPriceMatch as curatedDiscovery —"if we match prices, people trust exploring with us more"— so it passes the filter without resistance. That's exactly the dishonest label the rest of the module (lesson 4 in particular) teaches you to detect: when a bet's label starts sounding forced, it's usually because someone already knows, deep down, that bet doesn't belong, and is trying to dress up the translation instead of accepting the result.

Common mistakes

Delivering a roadmap that's a feature list with no strategic thread. What happens: the quarter's roadmap gets built as a list of feature names —fasterCheckout, recommendations, sellerTools—, each with its estimated date, but with no line saying which part of the strategy it responds to. Why it happens: writing the feature's name and a date is fast; explicitly writing which strategic dimension it serves requires this lesson's translation work, which many teams skip because "it's already understood." How to spot it: ask, for any line on your team's current roadmap, "which dimension of our strategy does this serve?" — if nobody can answer in one word, without hesitating, the roadmap is a feature list, not a strategic roadmap. How to fix it: require every bet to carry its servesDimensions before it even enters the priority conversation, exactly as you did with this lesson's three bets.

Labeling a bet with the dimension one wishes it served, not the one it actually serves. What happens: someone convinced of a bet —for whatever reason, technical enthusiasm, pressure from a specific client— labels it with the strategic dimension that would make it pass the filter, instead of the dimension it honestly fulfills. Why it happens: lesson 3's filter creates a perverse incentive if nobody watches the label's honesty — it's easier to dress up the translation than to accept that the favorite bet doesn't belong. How to spot it: if the connection between a bet and the dimension it claims to serve needs a long, elaborate explanation to sound convincing, be suspicious — honest connections, like sellerTools → sellerTrust in this example, explain themselves in one short sentence. How to fix it: have someone outside the team that proposed the bet review the label before it enters the filter — the same external-audit discipline you already used in module 4 to separate real differentiation from parity.

Not labeling at all, and leaving the connection to strategy implicit "in everyone's head." What happens: the team decides "we all know where we're going," and no bet gets formally labeled with the dimension it serves — the strategy stays a tacit consensus, not a written, verifiable criterion. Why it happens: labeling feels like unnecessary bureaucracy when the team is small and the strategy seems obvious to everyone present. How to spot it: ask two different people on the team to label the same bet with the dimension it serves, without consulting each other — if they give different answers, "we all know where we're going" was an illusion. How to fix it: the written label isn't bureaucracy — it's the only way for lesson 3's strategic filter to have something objective to evaluate, instead of depending on the team's collective memory never drifting out of alignment.

Exercises

Exercise 1 — Label a new bet. An engineer proposes building a push notification system that alerts a buyer when a seller they follow posts a new product. Which servesDimensions dimension would you assign it —curatedDiscovery, sellerTrust, catalogBreadth, price, deliverySpeed, or convenience— and why, in one sentence?

See solution

curatedDiscovery is the most honest label: a notification system based on following specific sellers is, literally, a form of curated discovery —it shows the buyer something relevant without them having to actively search for it—, not a general convenience improvement or a delivery-speed one. A reasonable alternative label would be sellerTrust if the central argument were "it deepens the relationship with already-established trusted sellers" — what matters in the exercise isn't the single correct answer, but that the justification holds up in one short sentence, without needing a paragraph of forced justification.

Exercise 2 — Find the dishonest label. A colleague labels a "volume discounts for frequent buyers" bet as curatedDiscovery, arguing that "a frequent buyer already trusts our curation, so the discount reinforces it." Why is this label suspicious under this lesson's criterion?

See solution

It's suspicious because the connection needs a long, elaborate chain of reasoning ("already trusts, so the discount reinforces") instead of a direct, short connection. A volume discount is, by its nature, a price lever —exactly the dimension Mercado's strategy decided not to fight on—, not curated discovery. The honest label would be price, which, correctly, would cause the bet to fall out in lesson 3's filter — and it's precisely that fallout the colleague is trying to avoid by disguising the label.

Exercise 3 — Design your own team's materials list. Think of three real initiatives on the radar of a team you know (yours, or a hypothetical one). For each one, write a one-word or short-phrase label indicating which part of that team's strategy it claims to serve. If you can't write a short, honest label for one of them, what does that tell you?

See solution

There's no single answer — the exercise evaluates the translation exercise itself. The most important signal: if you couldn't write a short, honest label for one of the three initiatives, that generally means one of two things — either the initiative doesn't actually have a clear connection to the strategy (and is a candidate to fall out in a real filter), or the team's strategy still isn't defined precisely enough to serve as a criterion, in which case the pending work isn't labeling better, but going back to modules 2 through 6 of this guide and pinning down "where we play and how we win" first.

Summary and next step

This lesson isolated the first step, almost always invisible, between the written strategy and the built roadmap: translating every candidate bet into an honest label —servesDimensions— declaring which part of the strategy it claims to serve. You saw, with three bets, that this label already reveals the module's full pattern: sellerTools and recommendations declare dimensions the Mercado strategy chose to win on; lowestPriceMatch declares, with total honesty, a dimension the strategy decided not to fight on.

Before moving on you should be able to: explain why a roadmap without this label is just a list of names, and recognize when a label sounds forced instead of honest.

Lesson 3 takes this label as input and builds the complete filter: the exact rule that separates a bet that belongs to the strategy from one that doesn't, no matter how good its riceScore is.

Resources