Módulo 8: Project Define Mercados Strategy

Proyecto final: define la estrategia de Mercado, de principio a fin

Descripción

Este es el cierre de la guía completa, y del arco entero de Product Engineering que empezó con product-thinking-for-engineers-guide. En las siete lecciones anteriores de este módulo construiste, capa por capa, el one-pager de estrategia de Mercado: la visión (lección 2), dónde juega y con qué margen gana (lección 3), cómo gana y cuánto tiempo le queda a ese terreno (lección 4), qué tan defendible es esa ventaja (lección 5), qué apuestas del backlog pertenecen a esa estrategia (lección 6), y cómo presentarlo todo junto (lección 7). Cada capa, hasta ahora, corrió su propio modelo por separado.

Este proyecto hace lo que ninguna lección anterior hizo: encadena los cuatro modelos ejecutables de la guía —positionFit (módulo 3), differentiationMap (módulo 4), moatScore (módulo 6) y strategicFilter (módulo 7)— en un solo pipeline, donde la salida de una capa alimenta la entrada de la siguiente. winOn y avoid —los dos valores que definen la estrategia de Mercado— ya no se declaran a mano: se derivan de la diferenciación real y de lo que la visión descarta. Y el roadmap final no solo dice qué apuestas pertenecen al juego —eso ya lo sabías desde la lección 6—, sino cuáles de ellas, además, están construyendo algo defendible, y cuáles todavía no.

Tu entregable tiene tres partes, y las tres se verifican con código: (1) el pipeline completo, con los cuatro modelos encadenados y la estrategia derivada, no declarada; (2) el roadmap final, cruzado contra la auditoría de moats; y (3) la lectura honesta de lo que ese cruce revela — el hallazgo que cierra la guía completa.

Conexión con el módulo. Este proyecto no introduce ningún modelo nuevo — reutiliza, verbatim, positionFit (módulo 3), differentiationMap (módulo 4), moatScore (módulo 6, inventario completo de ocho candidatos) y riceScore + strategicFilter (módulo 7, backlog completo de seis apuestas). Lo único genuinamente nuevo es la orquestación: el código que conecta la salida de un modelo con la entrada del siguiente, y una sola anotación adicional (deepensMoat) que el equipo agrega —a criterio propio, no inferida por ningún modelo— para cruzar el roadmap final contra la capa de moats.

Una analogía: el informe final del arquitecto, con cada columna trazada hasta su porqué

La lección 1 de este módulo abrió con la imagen del arquitecto que entrega, el día final, un solo documento donde cada decisión de diseño está trazada hasta el informe técnico que la justifica. Este proyecto es ese documento, terminado. No solo dice "esta columna es de tal grosor" (el roadmap final) — dice "esta columna es de tal grosor porque el ingeniero de suelos encontró tal resistencia en el terreno, y porque el presupuesto lo permitía sin sacrificar la estructura" (el pipeline completo, con cada capa alimentando a la siguiente). Un plano que solo mostrara el resultado, sin la cadena de porqués, no serviría para defender ninguna decisión ante un cliente escéptico. Este proyecto es la cadena completa, ejecutada de principio a fin, para que ninguna pregunta de "¿y esto por qué?" se quede sin una respuesta trazable hasta un modelo verificado.

La solución de referencia, verificada

Parte 1 — El pipeline completo, encadenado en Node

Los cuatro modelos, verbatim de sus módulos de origen, más la orquestación que los conecta: la visión (módulo 2) alimenta avoid; la diferenciación real (módulo 4) alimenta winOn; el filtro estratégico (módulo 7) corre sobre la estrategia derivada; y el resultado final se cruza contra la auditoría de moats (módulo 6) a través de deepensMoat, la anotación que el equipo agrega sobre el backlog.

// ===== CAPA 1: positionFit -- reutilizada verbatim del módulo 3 =====
function positionFit(target, product, alternatives) {
  const dims = Object.keys(target.weights).filter((d) => target.weights[d] > 0);
  const weightedScore = (c) => dims.reduce((sum, d) => sum + target.weights[d] * c.scores[d], 0);
  const productScore = weightedScore(product);
  const rivals = alternatives.map((a) => ({ name: a.name, score: weightedScore(a) }));
  const bestRival = rivals.reduce((a, b) => (b.score > a.score ? b : a));
  const byDimension = dims.map((d) => {
    const rivalBest = alternatives.reduce(
      (best, a) => (a.scores[d] > best.score ? { name: a.name, score: a.scores[d] } : best),
      { name: alternatives[0].name, score: -Infinity }
    );
    return { dimension: d, weight: target.weights[d], productScore: product.scores[d], bestRivalScore: rivalBest.score, bestRivalName: rivalBest.name, wins: product.scores[d] > rivalBest.score };
  });
  return { segment: target.name, productWeightedScore: Number(productScore.toFixed(2)), bestRival: bestRival.name, bestRivalWeightedScore: Number(bestRival.score.toFixed(2)), fitsSegment: productScore > bestRival.score, byDimension };
}

// ===== CAPA 2: differentiationMap -- reutilizada verbatim del módulo 4 =====
function differentiationMap(us, competitors, dimensions) {
  const REAL_DIFF_MARGIN = 2;
  return dimensions.map((dim) => {
    const usScore = us.scores[dim.key];
    const rivals = competitors.map((c) => ({ name: c.name, score: c.scores[dim.key] }));
    const best = rivals.reduce((a, b) => (b.score > a.score ? b : a));
    const gap = usScore - best.score;
    let verdict;
    if (gap >= REAL_DIFF_MARGIN) verdict = 'differentiation';
    else if (gap <= -REAL_DIFF_MARGIN) verdict = 'gap';
    else verdict = 'parity';
    return {
      dimension: dim.key,
      mattersToSegment: dim.matters,
      usScore,
      bestCompetitor: best.name,
      bestCompetitorScore: best.score,
      verdict,
    };
  });
}

// ===== CAPA 3: moatScore -- reutilizada verbatim del módulo 6 =====
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 ? ', con decay local' : ', sin decay'}`;
      break;
    }
    case 'switchingCost': {
      const { depth } = advantage;
      const depthScore = { contractual: 3, habit: 5, dataAndWorkflow: 8 };
      durability = depthScore[depth] ?? 3;
      rationale = `switching cost de profundidad '${depth}'`;
      break;
    }
    case 'scaleEconomies': {
      const { fixedCostShare } = advantage;
      durability = Math.round(fixedCostShare * 10);
      rationale = `economias de escala con ${Math.round(fixedCostShare * 100)}% de costo fijo`;
      break;
    }
    case 'dataMoat': {
      const { feedbackLoop, uniqueToUs } = advantage;
      durability = feedbackLoop ? 7 : 2;
      if (feedbackLoop && uniqueToUs) durability += 2;
      rationale = feedbackLoop
        ? `los datos alimentan un loop que mejora el producto${uniqueToUs ? ' y son exclusivos' : ''}`
        : 'los datos se acumulan pero no retroalimentan el producto';
      break;
    }
    case 'brand': {
      const { pricingPower } = advantage;
      durability = pricingPower ? 6 : 2;
      rationale = pricingPower
        ? 'la marca cambia el comportamiento de compra (tolera precio o fricción)'
        : 'la marca es reconocida pero no cambia comportamiento de compra';
      break;
    }
    case 'feature': {
      const { timeToCopyWeekends } = advantage;
      durability = Math.max(0, Math.min(3, timeToCopyWeekends));
      rationale = `feature copiable en ~${timeToCopyWeekends} fin(es) de semana`;
      break;
    }
    default: {
      durability = 0;
      rationale = 'tipo de ventaja desconocido';
    }
  }

  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 };
}

// ===== CAPA 4: riceScore + strategicFilter -- reutilizadas verbatim del módulo 7 =====
function riceScore({ reach, impact, confidence, effort }) {
  return (reach * impact * confidence) / effort;
}

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)),
      deepensMoat: bet.deepensMoat,
    };
  });
}

// ===================================================================
// PASO 1 -- LA VISIÓN (módulo 2), sin cambios.
// ===================================================================
const vision = {
  statement: 'El mundo donde cualquier persona descubre en Mercado lo que no sabía que quería.',
  includes: ['curatedDiscovery', 'localSellerTrust', 'serendipity'],
  excludes: ['exactSkuSearchEngine', 'lowestPriceRace', 'genericMegastore'],
};

// ===================================================================
// PASO 2 -- DÓNDE JUGAR: positionFit (módulo 3), datos verbatim.
// ===================================================================
const mercado = { name: 'Mercado', scores: { curatedDiscovery: 9, sellerTrust: 8, catalogBreadth: 6, price: 5, deliverySpeed: 5, convenience: 6 } };
const genericMegastore = { name: 'genericMegastore', scores: { curatedDiscovery: 3, sellerTrust: 4, catalogBreadth: 9, price: 8, deliverySpeed: 9, convenience: 8 } };
const localShop = { name: 'localShop', scores: { curatedDiscovery: 6, sellerTrust: 9, catalogBreadth: 2, price: 4, deliverySpeed: 3, convenience: 3 } };
const explorers = { name: 'explorers', weights: { curatedDiscovery: 0.4, sellerTrust: 0.3, catalogBreadth: 0.1, price: 0.1, deliverySpeed: 0.05, convenience: 0.05 } };

const whereToPlay = positionFit(explorers, mercado, [genericMegastore, localShop]);

// ===================================================================
// PASO 3 -- CÓMO GANAR: differentiationMap (módulo 4), datos verbatim.
// ===================================================================
const mercadoDiff = { name: 'Mercado', scores: { catalogBreadth: 3, price: 3, deliverySpeed: 4, curatedDiscovery: 5, localSellerTrust: 5, appAnimationPolish: 5 } };
const genericMegastoreDiff = { name: 'genericMegastore', scores: { catalogBreadth: 5, price: 5, deliverySpeed: 4, curatedDiscovery: 2, localSellerTrust: 2, appAnimationPolish: 2 } };
const neighborhoodShop = { name: 'neighborhoodShop', scores: { catalogBreadth: 1, price: 3, deliverySpeed: 2, curatedDiscovery: 3, localSellerTrust: 3, appAnimationPolish: 1 } };
const dimensions = [
  { key: 'catalogBreadth', matters: false },
  { key: 'price', matters: false },
  { key: 'deliverySpeed', matters: true },
  { key: 'curatedDiscovery', matters: true },
  { key: 'localSellerTrust', matters: true },
  { key: 'appAnimationPolish', matters: false },
];

const howToWin = differentiationMap(mercadoDiff, [genericMegastoreDiff, neighborhoodShop], dimensions);

// ===================================================================
// PASO 4 -- MOATS: moatScore (módulo 6), inventario completo verbatim.
// ===================================================================
const moatCandidates = [
  { 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 },
];
const moatAudit = moatCandidates.map(moatScore);
const moatByName = Object.fromEntries(moatAudit.map((m) => [m.name, m]));

// ===================================================================
// PASO 5 -- LA ESTRATEGIA SE DERIVA, NO SE DECLARA A MANO.
// M4/M6 llaman a este pilar 'localSellerTrust'; M3/M7 lo llaman 'sellerTrust'.
// Mismo concepto, dos identificadores heredados de módulos distintos --
// el one-pager los reconcilia aquí, explícitamente, en vez de fingir que
// son cosas distintas.
// ===================================================================
const dimensionAlias = { localSellerTrust: 'sellerTrust' };
const winOn = howToWin
  .filter((d) => d.verdict === 'differentiation' && d.mattersToSegment)
  .map((d) => dimensionAlias[d.dimension] ?? d.dimension);

const avoidMap = { lowestPriceRace: 'price' };
const avoid = vision.excludes.map((e) => avoidMap[e]).filter(Boolean);

const mercadoStrategy = { winOn, avoid };

// ===================================================================
// PASO 6 -- EL FILTRO ESTRATÉGICO sobre el backlog (módulo 7), con la
// estrategia DERIVADA del paso 5 -- no la copia hardcodeada del módulo 7.
// deepensMoat es una anotación NUEVA de este proyecto: qué candidato de
// la auditoría de moats (paso 4) profundizaría esta apuesta si se
// construye bien -- un juicio del equipo, no algo que ningún modelo
// infiera solo. No cambia servesDimensions ni rice heredados de M7.
// ===================================================================
const backlog = [
  { feature: 'fasterCheckout', servesDimensions: ['convenience'], rice: { reach: 8000, impact: 2, confidence: 0.8, effort: 2 }, deepensMoat: 'fasterCheckout' },
  { feature: 'recommendations', servesDimensions: ['curatedDiscovery'], rice: { reach: 5000, impact: 1, confidence: 0.5, effort: 3 }, deepensMoat: 'curatedDiscovery' },
  { feature: 'sellerTools', servesDimensions: ['sellerTrust'], rice: { reach: 1200, impact: 2, confidence: 0.8, effort: 2 }, deepensMoat: 'sellerToolsWorkflow' },
  { feature: 'reviews', servesDimensions: ['sellerTrust'], rice: { reach: 6000, impact: 0.5, confidence: 0.8, effort: 1 }, deepensMoat: 'localSellerTrust' },
  { feature: 'improvedSearch', servesDimensions: ['catalogBreadth'], rice: { reach: 9000, impact: 1, confidence: 0.5, effort: 3 }, deepensMoat: null },
  { feature: 'lowestPriceMatch', servesDimensions: ['price'], rice: { reach: 9500, impact: 3, confidence: 0.8, effort: 3 }, deepensMoat: null },
];

const filtered = strategicFilter(backlog, mercadoStrategy).sort((a, b) => b.riceScore - a.riceScore);

// ===================================================================
// SALIDA
// ===================================================================
console.log('=== PASO 2: dónde jugar (positionFit) ===\n');
console.log(`segment: ${whereToPlay.segment} | productWeightedScore: ${whereToPlay.productWeightedScore} | bestRival: ${whereToPlay.bestRival} (${whereToPlay.bestRivalWeightedScore}) | fitsSegment: ${whereToPlay.fitsSegment}`);

console.log('\n=== PASO 3: cómo ganar (differentiationMap) ===\n');
const realDiffs = howToWin.filter((d) => d.verdict === 'differentiation' && d.mattersToSegment);
console.log(`Diferenciación real: ${realDiffs.map((d) => d.dimension).join(', ')}`);

console.log('\n=== PASO 4: moats (moatScore) sobre los pilares de la diferenciación ===\n');
console.table(realDiffs.map((d) => moatByName[d.dimension]).map(({ name, durability, verdict }) => ({ name, durability, verdict })));

console.log('\n=== PASO 5: la estrategia, derivada (no hardcodeada) ===\n');
console.log(`mercadoStrategy = ${JSON.stringify(mercadoStrategy)}`);

console.log('\n=== PASO 6: el filtro estratégico + el cruce con moats, sobre el backlog completo ===\n');
console.table(filtered.map((b) => ({
  feature: b.feature,
  inStrategy: b.inStrategy,
  riceScore: b.riceScore,
  deepensMoat: b.deepensMoat ?? 'ninguno',
  moatVerdict: b.deepensMoat ? moatByName[b.deepensMoat].verdict : 'n/a',
})));

const roadmap = filtered.filter((b) => b.inStrategy);
const rejected = filtered.filter((b) => !b.inStrategy);

console.log('\n=== El roadmap final de Mercado, con su respaldo de moat ===\n');
for (const b of roadmap) {
  const moatNote = b.deepensMoat
    ? `profundiza '${b.deepensMoat}' (${moatByName[b.deepensMoat].verdict}, durability ${moatByName[b.deepensMoat].durability})`
    : 'sin candidato a moat en el inventario';
  console.log(`- ${b.feature} (riceScore ${b.riceScore}): ${moatNote}`);
}

console.log(`\nRechazadas por el filtro (sin importar riceScore): ${rejected.map((b) => `${b.feature} (${b.riceScore})`).join(', ')}.`);

Qué esperar. Al correr el archivo con Node, la salida es exactamente esta:

=== PASO 2: dónde jugar (positionFit) ===

segment: explorers | productWeightedScore: 7.65 | bestRival: localShop (6) | fitsSegment: true

=== PASO 3: cómo ganar (differentiationMap) ===

Diferenciación real: curatedDiscovery, localSellerTrust

=== PASO 4: moats (moatScore) sobre los pilares de la diferenciación ===

┌─────────┬────────────────────┬────────────┬──────────────┐
│ (index) │        name        │ durability │   verdict    │
├─────────┼────────────────────┼────────────┼──────────────┤
│    0    │ 'curatedDiscovery' │     3      │ 'not-a-moat' │
│    1    │ 'localSellerTrust' │     6      │ 'weak-moat'  │
└─────────┴────────────────────┴────────────┴──────────────┘

=== PASO 5: la estrategia, derivada (no hardcodeada) ===

mercadoStrategy = {"winOn":["curatedDiscovery","sellerTrust"],"avoid":["price"]}

=== PASO 6: el filtro estratégico + el cruce con moats, sobre el backlog completo ===

┌─────────┬────────────────────┬────────────┬───────────┬───────────────────────┬──────────────┐
│ (index) │      feature       │ inStrategy │ riceScore │      deepensMoat      │ moatVerdict  │
├─────────┼────────────────────┼────────────┼───────────┼───────────────────────┼──────────────┤
│    0    │ 'lowestPriceMatch' │   false    │   7600    │       'ninguno'       │    'n/a'     │
│    1    │  'fasterCheckout'  │   false    │   6400    │   'fasterCheckout'    │ 'not-a-moat' │
│    2    │     'reviews'      │    true    │   2400    │  'localSellerTrust'   │ 'weak-moat'  │
│    3    │  'improvedSearch'  │   false    │   1500    │       'ninguno'       │    'n/a'     │
│    4    │   'sellerTools'    │    true    │    960    │ 'sellerToolsWorkflow' │    'moat'    │
│    5    │ 'recommendations'  │    true    │  833.33   │  'curatedDiscovery'   │ 'not-a-moat' │
└─────────┴────────────────────┴────────────┴───────────┴───────────────────────┴──────────────┘

=== El roadmap final de Mercado, con su respaldo de moat ===

- reviews (riceScore 2400): profundiza 'localSellerTrust' (weak-moat, durability 6)
- sellerTools (riceScore 960): profundiza 'sellerToolsWorkflow' (moat, durability 8)
- recommendations (riceScore 833.33): profundiza 'curatedDiscovery' (not-a-moat, durability 3)

Rechazadas por el filtro (sin importar riceScore): lowestPriceMatch (7600), fasterCheckout (6400), improvedSearch (1500).

Parte 2 — La lectura honesta del resultado

El roadmap es idéntico al del módulo 7 — y eso es la prueba de que el pipeline funciona. reviews > sellerTools > recommendations, con lowestPriceMatch, fasterCheckout e improvedSearch rechazados. Si el paso 5 en verdad deriva winOn y avoid de las capas anteriores, tiene que reproducir la misma estrategia que el módulo 7 verificó de forma independiente y hardcodeada. La coincidencia exacta no es casualidad — es la validación de que las cuatro capas de esta guía son, de verdad, consistentes entre sí.

Pero el cruce con moats revela algo que ningún módulo anterior, por sí solo, podía mostrarte. Las tres apuestas del roadmap final no son intercambiables, aunque las tres tengan inStrategy: true:

  • sellerTools profundiza sellerToolsWorkflow, un moat real (verdict: 'moat', durability: 8). Es la apuesta más fuerte de las tres: pertenece a la estrategia y construye algo que ya cruzó el umbral de defensibilidad.
  • reviews profundiza localSellerTrust, un weak-moat (verdict: 'weak-moat', durability: 6). Pertenece a la estrategia y avanza hacia un moat, pero todavía no llega.
  • recommendations profundiza curatedDiscovery, y el cruce confirma lo que la lección 5 ya adelantó: verdict: 'not-a-moat', durability: 3. Esta apuesta pertenece a la estrategia —refuerza exactamente la dimensión donde Mercado gana su segmento— y al mismo tiempo no está construyendo, todavía, ninguna defensa estructural.

Ningún módulo anterior podía producir esta lectura de tres niveles. El módulo 7, por sí solo, te habría dicho "las tres pertenecen, constrúyelas" y se habría detenido ahí — información correcta, pero incompleta. El módulo 6, por sí solo, te habría dicho "curatedDiscovery no es un moat" sin decirte si de todas formas vale la pena construir la apuesta que lo profundiza. Solo el pipeline completo, corriendo las cuatro capas sobre el mismo backlog, produce la pregunta con la precisión que un equipo de ingeniería real necesita: construye las tres — las tres pertenecen al juego — pero trata a recommendations con una urgencia distinta a las otras dos, porque la diferenciación que profundiza sigue siendo, hoy, un algoritmo copiable en unas semanas. El camino ya está señalado desde el módulo 6: conectar curatedDiscovery al mismo ciclo de datos que ya demostró funcionar en purchaseData (feedbackLoop: true, uniqueToUs: true, durability: 9) movería esa diferenciación de 'feature' a 'dataMoat' — la apuesta de ingeniería que este roadmap todavía no incluye, y que el equipo debería agregar a la conversación del próximo trimestre, no como una alternativa a recommendations, sino como su complemento necesario.

Y las tres apuestas rechazadas confirman su exclusión desde dos ángulos independientes, no solo uno. fasterCheckout no solo falla strategicFilter (no refuerza ninguna dimensión de winOn) — su propio candidato de moat, evaluado con el mismo criterio que todo lo demás, sale 'not-a-moat' con durability: 1, la puntuación más baja de todo el inventario. Dos modelos independientes, corridos sobre el mismo dato, llegan a la misma conclusión por caminos distintos: esta apuesta ni pertenece al juego ni construye nada defendible. Esa clase de confirmación cruzada —dos modelos distintos, un solo veredicto— es la señal más fuerte que un equipo de estrategia puede pedir antes de archivar una idea con buen RICE.

Errores comunes

Presentar el roadmap final sin la columna de deepensMoat. Qué pasa: el equipo entrega reviews > sellerTools > recommendations como si las tres apuestas fueran igual de sólidas, sin mencionar que solo una de las tres profundiza un moat ya construido. Por qué pasa: strategicFilter produce un resultado binario (inStrategy: true/false) que se siente completo por sí mismo — agregar una tercera dimensión de análisis (defensibilidad) se siente como complicar un resultado que ya parecía terminado. Cómo detectarlo: si tu roadmap final no distingue entre una apuesta que refuerza un moat real y una que refuerza una diferenciación todavía copiable, estás tratando tres apuestas de riesgo muy distinto como si fueran intercambiables. Cómo corregirlo: exige siempre el cruce completo de este proyecto — pertenencia a la estrategia y respaldo de moat, nunca solo la primera.

Interpretar curatedDiscovery: not-a-moat como una razón para NO construir recommendations. Qué pasa: alguien lee el resultado de este proyecto y concluye que, como curatedDiscovery no es un moat, recommendations debería sacarse del roadmap — confundiendo "todavía no es defendible" con "no vale la pena construirlo". Por qué pasa: un veredicto 'not-a-moat' suena, en una lectura rápida, como una señal de alarma que invita a descartar la apuesta completa. Cómo detectarlo: si tu equipo está considerando remover recommendations del roadmap por este resultado, revisaron mal la conclusión — recommendations sigue perteneciendo a la estrategia (inStrategy: true, confirmado por strategicFilter); lo que el resultado agrega es una urgencia adicional, no un veto. Cómo corregirlo: recuerda la distinción exacta de la Parte 2 — pertenencia y defensibilidad son preguntas distintas; un not-a-moat es una llamada a reforzar, no a abandonar.

Cerrar el proyecto sin conectar el hallazgo con una acción de ingeniería concreta. Qué pasa: el equipo presenta la tabla completa del pipeline, reconoce que curatedDiscovery no es moat, y ahí se detiene — sin agregar al backlog la apuesta específica que resolvería esa brecha (conectar la curaduría al ciclo de purchaseData). Por qué pasa: el pipeline entrega un diagnóstico completo y verificado, y se siente como que el trabajo terminó — falta el último paso, traducir el diagnóstico en una apuesta nueva de ingeniería. Cómo detectarlo: si nadie en tu equipo puede nombrar, después de correr este proyecto, una apuesta específica del próximo trimestre que movería curatedDiscovery hacia dataMoat, el resultado se quedó en diagnóstico puro. Cómo corregirlo: usa la Parte 2 de este proyecto como el punto de partida de la siguiente conversación de backlog — no el final de esta.

Ejercicios

Ejercicio 1 — Agrega una séptima apuesta que cierre la brecha. Un ingeniero propone discoveryDataLoop — conectar el algoritmo de curatedDiscovery al mismo ciclo de datos de compra de purchaseData —, con servesDimensions: ['curatedDiscovery'], rice: { reach: 4000, impact: 2, confidence: 0.6, effort: 4 } y deepensMoat: 'purchaseData'. Calcula su riceScore, determina si pasaría strategicFilter, y explica por qué su deepensMoat es distinto al de recommendations.

Ver solución

riceScore = (4000 × 2 × 0.6) / 4 = 4800 / 4 = 1200. Con reinforces: ['curatedDiscovery'] (no vacío, está en winOn) y conflicts: [], inStrategy sería true — entraría al roadmap por encima de sellerTools (960) pero por debajo de reviews (2400). Su deepensMoat es 'purchaseData', no 'curatedDiscovery', porque esta apuesta no es más curaduría — es la conexión de infraestructura que convierte la curaduría existente en parte del ciclo de datos que purchaseData ya demostró que funciona (verdict: 'moat', durability: 9). Si se construyera, la siguiente corrida de este pipeline debería reflejar curatedDiscovery con un type: 'dataMoat' en vez de 'feature' — el cambio de arquitectura que la Parte 2 de este proyecto identificó como pendiente.

Ejercicio 2 — Simula qué pasaría si sellerToolsWorkflow se erosionara. Si Mercado migrara sus herramientas de vendedores a una integración más superficial (depth: 'habit' en vez de 'dataAndWorkflow', como en el Ejercicio 2 de la lección 5), ¿cambiaría el moatVerdict de sellerTools en la tabla final de este proyecto? ¿Debería seguir en el roadmap de todas formas?

Ver solución

Sí cambiaría: con depthScore['habit'] = 5, durability bajaría de 8 a 5, y verdict bajaría de 'moat' a 'weak-moat'. sellerTools seguiría en el roadmap de todas formas —strategicFilter no depende del resultado de moatScore, sigue evaluando solo servesDimensions contra winOn/avoid, así que inStrategy seguiría siendo true—, pero pasaría de ser "la apuesta más sólida de las tres" a compartir el mismo nivel de fragilidad que reviews. Este ejercicio muestra que el cruce de este proyecto no es estático: una decisión de arquitectura tomada meses después de este análisis puede cambiar por completo qué tan urgente es cada apuesta del roadmap, sin cambiar en absoluto si esa apuesta pertenece a la estrategia.

Ejercicio 3 — Presenta el cierre completo de la guía al equipo fundador de Mercado. Escribe, en un párrafo, cómo presentarías el resultado de este proyecto —el pipeline completo, el roadmap con su respaldo de moat, y la recomendación sobre recommendations— como el cierre de los ocho módulos completos de esta guía.

Ver solución

Un ejemplo de respuesta: "Ocho módulos después, esto es lo que sabemos con certeza, no con intuición: ganamos el segmento que elegimos, con un margen medible. Ganamos por dos razones concretas, no por sensación general de calidad. Ese terreno está despejado hoy, con fecha de vencimiento en tres años si no lo defendemos. Ya tenemos cuatro moats reales construidos, por cuatro mecanismos independientes. Y cuando cruzamos todo eso contra nuestro backlog del trimestre, tres apuestas pertenecen al juego que decidimos jugar — pero no las tres construyen lo mismo: sellerTools profundiza un moat que ya existe, reviews construye hacia uno que casi llega, y recommendations, aunque absolutamente correcta de construir, todavía no está blindando nuestra diferenciación central contra una copia rápida. Nuestra recomendación no es sacar recommendations del roadmap — es agregar, al lado, la apuesta de ingeniería que conecta nuestra curaduría al mismo ciclo de datos que ya sabemos que funciona. Esa es la diferencia entre ejecutar bien la estrategia correcta y solo ejecutar bien, sin preguntarnos si el terreno bajo nuestros pies sigue siendo nuestro dentro de un año."

Resumen y siguiente paso

En este proyecto encadenaste, por primera vez en toda la guía, los cuatro modelos ejecutables de product-strategy-for-engineers-guide en un solo pipeline: positionFit confirmó que Mercado gana su segmento (fitsSegment: true, margen 1.65); differentiationMap aisló la diferenciación real (curatedDiscovery, localSellerTrust); moatScore auditó esos dos pilares y encontró que uno es weak-moat y el otro todavía no es moat; y strategicFilter, con una estrategia derivada de las dos capas anteriores —no declarada a mano—, reprodujo exactamente el roadmap del módulo 7 (reviews > sellerTools > recommendations). El cruce final entre el roadmap y la auditoría de moats reveló el hallazgo que cierra toda la guía: las tres apuestas pertenecen a la estrategia, pero solo una construye, hoy, algo ya defendible — y la diferenciación central de Mercado sigue esperando la apuesta de ingeniería que la convierta en moat.

Con esto cierras la guía completa: product-strategy-for-engineers-guide, los ocho módulos, de la visión al roadmap ejecutado.

El arco completo de Product Engineering. Empezaste este ecosistema en product-thinking-for-engineers-guide, aprendiendo a priorizar un backlog con RICE, dimensionar oportunidades y recortar al MVP correcto — el "cómo se juega" táctico. Esta guía te dio el "qué juego jugamos": la visión, el segmento, la diferenciación, los moats, y el filtro que decide qué del backlog táctico sirve a la dirección elegida. Las guías hermanas completan el resto del ciclo: product-discovery-and-prototyping-guide valida con usuarios reales las suposiciones que aquí se declararon como estrategia; product-metrics-and-experimentation-guide mide, con rigor estadístico, si lo que construiste realmente funcionó; y shipping-and-iterating-products-guide cierra el ciclo con el lanzamiento y la iteración. Con las siete piezas de esta guía —y las de product-thinking-for-engineers-guide antes que ella—, ya sabes decidir qué construir y por qué, con evidencia trazable en cada paso.

Hacia dónde sigues: Fullstack, para construir. Todo lo que esta guía y su guía hermana te enseñaron responde una pregunta: qué apuestas merecen convertirse en código. La pregunta que sigue —cómo se construye eso, técnicamente, con criterio de ingeniería real— pertenece al ecosistema Fullstack. Si nunca construiste una interfaz ni un backend de producción, empieza por web-fundamentals-html-css-guide; si ya programas y quieres el modelo mental moderno de construcción de producto, react-fundamentals-guide y nextjs-app-router-guide son el punto de entrada natural. Cualquiera de las tres apuestas que sobrevivieron el filtro de este proyecto —reviews, sellerTools, recommendations— es, a partir de aquí, un caso real de "ya sabemos qué construir y por qué; ahora construyámoslo bien".

Recursos

  • Roger Martin, "Decoding the Strategy Choice Cascade" — rogermartin.medium.com/decoding-the-strategy-choice-cascade-475d40555eb1. La cascada completa de Playing to Win, ahora que corriste tu propia versión ejecutable de principio a fin para Mercado. En inglés.
  • Melissa Perri, Escaping the Build Traporeilly.com/library/view/escaping-the-build/9781491973767. El diagnóstico completo de construir sin estrategia, resuelto aquí con un pipeline verificable de principio a fin, no solo con un filtro aislado. En inglés.
  • Marty Cagan (Silicon Valley Product Group), "Product Strategy" — svpg.com/product-strategy-overview. Cagan cierra el argumento de la guía completa: la estrategia de producto solo vale el día que decide, con evidencia, qué se construye y qué no — exactamente lo que produjo este proyecto. En inglés.
  • Hamilton Helmer, 7 Powers7powers.com. El vocabulario de moats que, cruzado contra el filtro estratégico en este proyecto, reveló la brecha más importante del roadmap final de Mercado. En inglés.