Module 6: Moats And Defensibility

Mini-project: Mercado's moat audit

Description

It's time to bring the whole module together into a single artifact: Mercado's complete moat audit. You learned to precisely define what a moat is and what it isn't (L2), covered the five types that can actually reach 'moat' —network effects (L3), switching costs (L4), data and economies of scale (L5)—, saw why a feature never crosses the threshold no matter how much it cost to build (L6), and saw that an advantage's type isn't decided by strategy, it's decided by an architecture decision made by an engineer (L7). In this project you run moatScore on Mercado's complete inventory of candidate advantages —eight in total, gathered from across the guide: the vision (module 2), the differentiation (module 4), and the ones this module named one by one— and close with the verdict that result demands: which are real moats, which barely make it, and which, in all honesty, aren't ones yet.

Your deliverable has three parts, and all three are verified with code, not just written up: (1) the complete inventory of eight candidates, with their type and parameters; (2) the complete audit, run with moatScore; and (3) the final classification into three groups —real moats, weak moats, and what isn't a moat— with an honest read on what each group means for what Mercado should defend, and what it shouldn't mistake for defense.

Connection to the module. This project doesn't introduce any new type — it brings together, in a single verified audit, the six types moatScore has recognized since lesson 2. It's also the bridge to the rest of the guide: the inventory you build here —what's a real moat and what isn't— is exactly the input module 7 needs for strategicFilter: a backlog bet that deepens a real moat deserves different priority than one that just polishes a copyable feature.

An analogy: the military engineer who inspects the whole castle

The module opened with two castles that looked almost identical from the road. This project is the moment to send a military engineer to inspect, structure by structure, an entire castle —not just the tower everyone assumes is the strongest, nor just the moat already known to be real. The engineer walks every wall, every door, every tower, and runs the same test on each: strikes the stone, measures the water, checks the foundation — without being impressed by how pretty a facade looks or discouraged because a structure has no fancy name. At the end of the walkthrough, they hand over a single document: which parts of the castle withstand a serious siege, and which parts are, in all honesty, well-painted decoration that was never put to the test.

That's exactly what you're going to do in this project: you're not just going to audit sellerNetwork and purchaseData —the two "obvious" candidates the module repeated over and over—, you're going to apply the same criterion to all of Mercado's inventory, including the differentiation module 4 proudly celebrated. An honest military engineer doesn't skip the castle's most photographed tower just because everyone assumes it's the strongest.

The reference solution, verified

Part 1 — The complete inventory, eight candidates

We gather eight of Mercado's candidate advantages, collected from across the guide. Four you already know by name: sellerNetwork (the seller network, module 1 and lesson 2), purchaseData (purchase data, lessons 2 and 5), fasterCheckout (the module 1 backlog item, evaluated as a feature in lesson 6), and curatedDiscovery (module 4's central differentiation, evaluated here as the pure algorithm, without the data loop lesson 6 showed it's missing). Four are new to the audit: logisticsNetwork (the warehouse and route network, type scaleEconomies, from lesson 5), sellerToolsWorkflow (the seller dashboard's deep integration, type switchingCost, from lessons 4 and 7), localSellerTrust (the trust in local sellers the vision —module 2— explicitly named as one of its includes, evaluated here as type brand), and mercadoBrand (Mercado's general brand recognition, with no pricing power, as a control case).

const candidates = [
  { name: 'sellerNetwork', type: 'networkEffect', sides: 2, localDecay: false },
  { name: 'purchaseData', type: 'dataMoat', feedbackLoop: true, uniqueToUs: true },
  { name: 'logisticsNetwork', type: 'scaleEconomies', fixedCostShare: 0.8 },
  { name: 'sellerToolsWorkflow', type: 'switchingCost', depth: 'dataAndWorkflow' },
  { name: 'localSellerTrust', type: 'brand', pricingPower: true },
  { name: 'curatedDiscovery', type: 'feature', timeToCopyWeekends: 3 },
  { name: 'fasterCheckout', type: 'feature', timeToCopyWeekends: 1 },
  { name: 'mercadoBrand', type: 'brand', pricingPower: false },
];

Check the inventory against the module's criteria before continuing: it includes the five types that can actually reach moat (L2 through L5) and the control type (L6), it doesn't stop at just the module's two most-repeated advantages, and it explicitly includes M4's differentiation instead of assuming, without testing it, that "it's already known" to be a moat.

Part 2 — The complete audit, run in Node

We run moatScore on the complete inventory and group the result into the three possible verdicts.

// Pedagogical model: scores the DURABILITY (0-10) of a competitive advantage.
// Reused unchanged from lesson 2 -- this project runs it over Mercado's
// COMPLETE inventory of moat candidates.
function moatScore(advantage) {
  const { name, type } = advantage;
  let durability;
  let rationale;

  switch (type) {
    case 'networkEffect': {
      const { sides, localDecay } = advantage;
      durability = sides >= 2 ? 8 : 5;
      if (localDecay) durability -= 3;
      rationale = `network effect ${sides}-sided${localDecay ? ', with local decay' : ', no decay'}`;
      break;
    }
    case 'switchingCost': {
      const { depth } = advantage;
      const depthScore = { contractual: 3, habit: 5, dataAndWorkflow: 8 };
      durability = depthScore[depth] ?? 3;
      rationale = `switching cost of depth '${depth}'`;
      break;
    }
    case 'scaleEconomies': {
      const { fixedCostShare } = advantage;
      durability = Math.round(fixedCostShare * 10);
      rationale = `economies of scale with ${Math.round(fixedCostShare * 100)}% fixed cost`;
      break;
    }
    case 'dataMoat': {
      const { feedbackLoop, uniqueToUs } = advantage;
      durability = feedbackLoop ? 7 : 2;
      if (feedbackLoop && uniqueToUs) durability += 2;
      rationale = feedbackLoop
        ? `the data feeds a loop that improves the product${uniqueToUs ? ' and is exclusive' : ''}`
        : 'the data accumulates but doesn\'t feed back into the product';
      break;
    }
    case 'brand': {
      const { pricingPower } = advantage;
      durability = pricingPower ? 6 : 2;
      rationale = pricingPower
        ? 'the brand changes purchase behavior (tolerates price or friction)'
        : 'the brand is recognized but doesn\'t change purchase behavior';
      break;
    }
    case 'feature': {
      const { timeToCopyWeekends } = advantage;
      durability = Math.max(0, Math.min(3, timeToCopyWeekends));
      rationale = `feature copyable in ~${timeToCopyWeekends} weekend(s)`;
      break;
    }
    default: {
      durability = 0;
      rationale = 'unknown advantage type';
    }
  }

  durability = Math.max(0, Math.min(10, durability));
  const verdict = durability >= 7 ? 'moat' : durability >= 4 ? 'weak-moat' : 'not-a-moat';
  return { name, type, durability, verdict, rationale };
}

const candidates = [
  { name: 'sellerNetwork', type: 'networkEffect', sides: 2, localDecay: false },
  { name: 'purchaseData', type: 'dataMoat', feedbackLoop: true, uniqueToUs: true },
  { name: 'logisticsNetwork', type: 'scaleEconomies', fixedCostShare: 0.8 },
  { name: 'sellerToolsWorkflow', type: 'switchingCost', depth: 'dataAndWorkflow' },
  { name: 'localSellerTrust', type: 'brand', pricingPower: true },
  { name: 'curatedDiscovery', type: 'feature', timeToCopyWeekends: 3 },
  { name: 'fasterCheckout', type: 'feature', timeToCopyWeekends: 1 },
  { name: 'mercadoBrand', type: 'brand', pricingPower: false },
];

console.log('=== Mercado\'s moat audit: 8 candidates, one criterion ===\n');
const audit = candidates.map(moatScore);
console.table(audit);

const realMoats = audit.filter((a) => a.verdict === 'moat');
const weakMoats = audit.filter((a) => a.verdict === 'weak-moat');
const notMoats = audit.filter((a) => a.verdict === 'not-a-moat');

console.log(`\nReal moats (${realMoats.length}/${candidates.length}): ${realMoats.map((a) => a.name).join(', ')}`);
console.log(`Weak moats (${weakMoats.length}/${candidates.length}): ${weakMoats.map((a) => a.name).join(', ')}`);
console.log(`Not a moat (${notMoats.length}/${candidates.length}): ${notMoats.map((a) => a.name).join(', ')}`);

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

=== Mercado's moat audit: 8 candidates, one criterion ===

┌─────────┬───────────────────────┬──────────────────┬────────────┬──────────────┬──────────────────────────────────────────────────────────────────────────┐
│ (index) │         name          │       type       │ durability │   verdict    │                                rationale                                 │
├─────────┼───────────────────────┼──────────────────┼────────────┼──────────────┼──────────────────────────────────────────────────────────────────────────┤
│    0    │    'sellerNetwork'    │ 'networkEffect'  │     8      │    'moat'    │                   'network effect 2-sided, no decay'                     │
│    1    │    'purchaseData'     │    'dataMoat'    │     9      │    'moat'    │  'the data feeds a loop that improves the product and is exclusive'      │
│    2    │  'logisticsNetwork'   │ 'scaleEconomies' │     8      │    'moat'    │               'economies of scale with 80% fixed cost'                   │
│    3    │ 'sellerToolsWorkflow' │ 'switchingCost'  │     8      │    'moat'    │            "switching cost of depth 'dataAndWorkflow'"                   │
│    4    │  'localSellerTrust'   │     'brand'      │     6      │ 'weak-moat'  │ 'the brand changes purchase behavior (tolerates price or friction)'      │
│    5    │  'curatedDiscovery'   │    'feature'     │     3      │ 'not-a-moat' │                'feature copyable in ~3 weekend(s)'                       │
│    6    │   'fasterCheckout'    │    'feature'     │     1      │ 'not-a-moat' │                'feature copyable in ~1 weekend(s)'                       │
│    7    │    'mercadoBrand'     │     'brand'      │     2      │ 'not-a-moat' │     'the brand is recognized but doesn't change purchase behavior'       │
└─────────┴───────────────────────┴──────────────────┴────────────┴──────────────┴──────────────────────────────────────────────────────────────────────────┘

Real moats (4/8): sellerNetwork, purchaseData, logisticsNetwork, sellerToolsWorkflow
Weak moats (1/8): localSellerTrust
Not a moat (3/8): curatedDiscovery, fasterCheckout, mercadoBrand

Part 3 — The honest read of the result

Four real moats, from four different mechanisms. sellerNetwork (two-sided network effect), purchaseData (data with a real loop), logisticsNetwork (a genuine economy of scale), and sellerToolsWorkflow (earned, not imposed, switching cost) cross the threshold of 7, each for a different structural reason. This alone is already better news than a superficial glance would have predicted: Mercado doesn't depend on a single type of advantage — it has four independent mechanisms, and a competitor who managed to erode one would still face the other three.

One weak moat, exactly where a hasty intuition would have called it strong. localSellerTrust —explicitly part of Mercado's vision since module 2— gets durability: 6: a real brand, with pricing power, but below the full-moat threshold. It's not a result to dismiss or to inflate — it's honest information that this advantage, today, is real but fragile, and a natural candidate for deepening (perhaps by connecting it to a switching-cost or data mechanism, the same logic from lesson 7).

The result that should give anyone on the team the most pause: curatedDiscovery is not a moat. The differentiation module 4 celebrated as the heart of Mercado's value proposition —"you discover what you didn't know you wanted"— gets durability: 3, evaluated as the pure curation algorithm. This doesn't invalidate module 4: the differentiation is still real and still serves the segment better than the alternatives. What this result says, precisely, is that this differentiation isn't protected yet — today it lives as code any competitor with a good team could replicate in a few weeks, not as a structural mechanism. Lesson 7 already showed the path: connecting curatedDiscovery to the purchaseData loop —which is a real moat, durability: 9— would move that differentiation from 'feature' to 'dataMoat', and it's exactly the kind of engineering bet module 7 (strategicFilter) will evaluate against the rest of Mercado's backlog.

Common mistakes

Auditing only the module's "famous" advantages and leaving blind spots. What happens: the team repeats the analysis of sellerNetwork and purchaseData —the two candidates that appeared over and over in the lessons— and calls the audit closed, without applying the same criterion to the differentiation from other modules or to the brand, which were never formally put through moatScore. Why it happens: repeated examples feel "already solved," and it's more comfortable to confirm what's already known than to test what was assumed without verifying. How to spot it: if your audit inventory has fewer than six candidates, or excludes the product's central differentiation, the audit has blind spots. How to fix it: require the inventory to cover, at minimum, one advantage from each earlier module of the guide —vision, differentiation, competition— before calling it complete, as this project did with curatedDiscovery and localSellerTrust.

Treating weak-moat as if it were the same as moat or the same as not-a-moat. What happens: when presenting results, the team collapses localSellerTrust (weak-moat) into the same category as the four real moats —"we have five moats"— or, in the other direction, dismisses it along with the features —"we only have four things worth anything"—, losing the specific information the intermediate verdict provides. Why it happens: a three-level classification is more awkward to communicate than a two-level one, and the temptation to simplify to "yes or no" erases exactly the nuance the model worked to capture. How to spot it: if results communicated to other teams use only two categories where the model produced three, real information was lost in translation. How to fix it: always communicate all three groups separately, with the weak-moat explicitly labeled "real but fragile, candidate for deepening" — neither a guaranteed moat, nor a disposable feature.

Closing the audit without connecting it to what to build next. What happens: the team delivers the complete moatScore table, presents it in a meeting, and stops there — without translating the result into a concrete recommendation about which backlog initiatives to prioritize to defend the real moats or deepen the weak ones. Why it happens: the audit itself feels like a complete deliverable —there's a table, there are numbers, there are verdicts—, and the step of connecting that diagnosis to a real engineering decision is missing. How to spot it: if nobody on the team can name, after seeing this audit, a single backlog bet that should move up in priority for deepening a real moat, the analysis stayed pure diagnosis. How to fix it: use this project's result as the input to module 7 —strategicFilter over the same Mercado backlog you already know (fasterCheckout, recommendations, sellerTools, reviews, improvedSearch)— to decide, with this moat inventory already done, which bets serve the strategy and which fall out, even if they score well on RICE.

Exercises

Exercise 1 — Add a ninth candidate. Mercado is evaluating launching a certification program for outstanding sellers —a visible badge that requires meeting certain quality and response-time standards. Before anyone builds anything, what moatScore type would you assign it, and with what parameters? Write the data object following the inventory's pattern, add it to the candidates array, and predict its durability and verdict before running the code.

See solution

There's no single correct answer — it depends on how the program is built, which is exactly lesson 7's point. A reasonable version, evaluated as described (a visible badge, with no additional mechanism): { name: 'sellerCertificationBadge', type: 'brand', pricingPower: false } — it's a trust signal for the buyer, but as described it doesn't say whether it changes purchase behavior (do buyers pay more or choose a certified seller more often?) or feed back into any other system. With pricingPower: false, durability: 2, verdict: 'not-a-moat' — the same result as mercadoBrand. If, instead, the certification fed the search ranking (as exercise 3 in lesson 5 proposed for reviews), the correct type would become dataMoat with feedbackLoop: true, and the result would change completely — the same lesson from 7, applied to a new candidate.

Exercise 2 — The erosion scenario. Imagine that, within two years, MegaStoreGenerico launches its own logistics system with its own warehouses, cutting its shipping cost almost to Mercado's level. If that happened, which candidate in this inventory would lose its 'moat' verdict, and what new fixedCostShare would roughly correspond to the verdict falling to 'weak-moat'?

See solution

The affected candidate is logisticsNetwork. A competitor building its own infrastructure doesn't directly change Mercado's fixedCostShare —Mercado would keep the same cost structure—, but if the exercise is read as "Mercado's relative advantage erodes because it's no longer the only one with that cost structure," the right way to model it in moatScore would be to recognize that an economy of scale's real durability depends on a competitor not being able to easily replicate it — and here it can. Using the literal formula, for durability to fall from 8 to a 'weak-moat' (durability between 4 and 6), fixedCostShare would need to drop to a value between 0.4 and 0.6 — for example, fixedCostShare: 0.5 gives durability: 5. The practical lesson: the model scores Mercado's cost structure, but whether that structure remains a relative advantage against a specific competitor is an additional layer of analysis the strategy team still has to do with judgment, not just the formula.

Exercise 3 — Present the audit to Mercado's founding team. Write, in a paragraph, how you'd present this complete audit to the founding team, including what concrete recommendation you'd make about curatedDiscovery —the table's most uncomfortable result— and about what to do with localSellerTrust, the only weak moat.

See solution

A sample answer: "We audited the eight advantages most often mentioned when we talk about why Mercado is going to win, with the same criterion for each: does this survive someone attacking it seriously? The good news: we have four real moats, from four distinct and independent mechanisms —our seller network, our purchase data, our logistics, and the depth of integration of our seller tools. The news that demands a decision: our curation, the central piece of why we say we're different, isn't a moat today — it's a good algorithm any competitor with a good engineering team could replicate in a few weeks. We're not proposing abandoning curation; we're proposing prioritizing, next quarter, connecting it to the same purchase-data loop we already know works, so it stops being a feature and becomes the fifth defensible piece. And trust in local sellers, though real, is halfway there — it's worth investing in deepening it before we count on it as if it were already a complete moat."

Summary and next step

In this mini-project you brought the whole module together into a single audit: eight of Mercado's moat candidates, gathered from across the guide, evaluated with the same criterion —moatScore— with no exceptions or favoritism for what's repeated or celebrated. The result: four real moats through four distinct mechanisms, one real but fragile weak moat, and the project's most important finding — the differentiation module 4 celebrated as Mercado's heart still isn't protected by any structural mechanism. With this you close module 6.

You now have, for any product you analyze in your own work, a complete instrument for answering the question that opened the module: "is this a moat, or is it decoration?" — with an executable criterion, not just an impression.

Where you go next. You now know what really defends Mercado and what doesn't yet. The next question: how does all of this —vision, positioning, differentiation, competition, and now moats— translate into what to build first? That's the question of module 7 (strategy-to-roadmap): the strategic filter, strategicFilter, which crosses this same moat inventory against the Mercado backlog you already know (fasterCheckout, recommendations, sellerTools, reviews, improvedSearch) to decide which bets serve the strategy —and deepen a real moat— and which fall out, even if they score well on RICE.

Resources

  • Hamilton Helmer, 7 Powers: The Foundations of Business Strategy7powers.com. The book that gave the whole module its technical vocabulary — network economies, switching costs, scale economies, and branding, the same four mechanisms that turned out to be real moats in this audit. In English.
  • Investopedia, "Economic Moat" — investopedia.com/terms/e/economicmoat.asp. The complete moat metaphor, from Warren Buffett to Morningstar's ratings, worth rereading now that you have Mercado's complete inventory classified with the same criterion. In English.
  • Roger Martin, "Playing to Win" — rogerlmartin.com/lets-read/playing-to-win. Module 1's "where to play / how to win" framework, a reminder that a moat inventory disconnected from a "how to win" decision stays diagnosis — the exact bridge to module 7. In English.