《独立开发者的商业指南·合同、应收与风险》13.3 卷二评审与进入卷三

卷二的最后一节用附录 C 的 46 项清单给三案例打分:LedgerLite 78、Tidecast 62、Nord Studio 50。分数不是目的,目的是把最弱的组映射到卷三的具体章节,给出进入卷三前的三个动作,并以融资结构、退出路径、交割条件三个交接问题收尾。

以下情境为教学假设,人物与数字不代表经核实的真实案例。

卷二写了 12 章,从合同结构一路写到保险、IP、渠道与业务连续性。这一节做收口:用附录 C 的 46 项清单给三个案例打分,看分数落在哪一档,再把最弱的组映射到卷三的具体章节。最后不写总结陈词,而是留三个交接问题——它们决定卷三从哪一章开始读。

六组清单:从条款到分数

附录 C 把卷二收成六组、46 项、满分 92 分。每组按 0、1、2 三档评分:2 分是有书面证据且金额可复算,1 分是有证据但不完整,0 分是拿不出证据。组内条目与证据要求见附录 C,正文只保留组级分数和权重。

组对应章节满分这一组在问什么
合同结构第 1–2 章20八个部分是否齐全,每个部分有没有数字
关键条款第 2 章16责任上限、续约窗口、SLA 抵扣能不能算出金额
应收与坏账第 3–4 章14应收能不能收回,准备、催收与前置保护是否匹配
争议与保险第 5–6 章14出事之后能主张多少,保险实际赔多少
IP 与渠道第 7–9 章14资产能否转移,渠道净得与退出成本是否算过
依赖与连续性第 10–12 章14关键依赖、迁移成本、预案与责任人是否齐全

权重不是平均分的。合同结构 20 分,因为它决定合同能不能执行、能不能算钱;关键条款 16 分,因为它决定最坏损失;其余四组各 14 分,分别覆盖现金、尾部、资产转移与业务连续性。权重是附录 C 的固定口径,读者可以按自己的生意调整,但调整后要固定下来,否则跨期分数不可比。

评分规则只有一条:拿不出证据的项按 0 分。没有合同原件、没有账龄表、没有保单、没有退出条款,都算 0 分;「大概有」「应该在邮箱里」不算证据。这条规则会让分数偏低,但偏低比虚高有用——它指向的是可以补的材料,而不是一个让人安心的数字。

三案例的评分

把三案例代入附录 C,得到下表。分数是教学示例,用于演示评分方法,不是对案例的正式评价。

组满分LedgerLiteTidecastNord Studio
合同结构20181512
关键条款1614129
应收与坏账1412137
争议与保险1412109
IP 与渠道141176
依赖与连续性141157
合计92786250
得分率84.8%67.4%54.3%
评级健康需关注高风险

LedgerLite 78/92,84.8%,落在健康档。合同结构 18/20 是三家里最高的:企业订阅协议、DPA、Net 15、12 个月费用上限、99.5% 与 10% 抵扣都有书面落点。失分集中在终止过渡、上限之外的赔偿、开源与 DPA 维护成本,以及云 60%、支付 25% 的依赖。它的最弱组不是合同,而是依赖与连续性(11/14):合同能算钱,但云和支付账号不在自己手里。

Tidecast 62/92,67.4%,落在需关注档。应收与坏账 13/14 是三家里最高的,因为平台月结把应收压到接近零;合同结构 15/20 已经接近平台标准协议的上限。真正拖低总分的是依赖与连续性(5/14):Steam 占销量 80%,没有保险,平台条款不可谈,90 天收入暴露 $19,079。它的高分项和低分项指向同一件事——平台替它收了钱,也替它承担了风险。

Nord 50/92,54.3%,落在高风险档。应收与坏账 7/14 最低:Net 30、8% 逾期、2% 坏账准备;IP 与渠道 6/14 也最低:前 3 家客户 48%、转介绍 55%,把回款和收入来源绑在同一批人身上。合同结构 12/20、关键条款 9/16,说明它的弱项不是「不会写合同」,而是「生意形态让条款难以转移」。这也解释了 3.0 倍 SDE 与 4.5 倍 SDE 的差距。

分数之间的差距不是经营水平的排序。Tidecast 的 62 分高于 Nord 的 50 分,但 Tidecast 的 SDE 是 $121,171,Nord 只有 $34,320;Nord 的生意更小、更依赖人,所以同样的缺口占 SDE 的比例更高。清单衡量的是「合同与风险能不能被第三方复核」,不是「谁赚得多」。

最弱的组指向卷三哪一章

卷三解决的是「生意怎么定价、怎么交割、怎么退出」。把每组最弱的项映射到卷三,就得到一张入场任务表。注意映射的是「缺口会在哪里被定价」,不是「缺口应该在哪里修」;修缺口是卷二的事,定价是卷三的事。

案例最弱的组得分卷三对应章节缺口会在哪里变成价格
LedgerLite依赖与连续性11/14(78.6%)第 8 章 8.2 客户、合同与账号迁移云 60%、支付 25% 的账号迁移进入交割条件
Tidecast依赖与连续性5/14(35.7%)第 8 章 8.2 客户、合同与账号迁移Steam 账号、商店页与结算关系决定收入能否延续
Nord StudioIP 与渠道6/14(42.9%)第 6 章 6.3 技术与知识产权尽调交付物归属、转介绍关系与客户集中进入尽调
Nord Studio应收与坏账7/14(50.0%)第 6 章 6.1 财务尽调Net 30、8% 逾期与 2% 准备进入营运资金调整

LedgerLite 的 IP 与渠道也是 11/14,和依赖与连续性并列最低。这里选连续性,是因为附录 C 把第六组设为交叉校验组:合同矩阵和敞口表都说「条款可控」,但云与支付账号不在公司手里,交割后收入可能断。买方不会因为一份 DPA 就忽略账号迁移;它会在交割清单里逐项确认云账号、支付账号、域名和回调地址能不能转。

Tidecast 的最弱组没有争议:依赖与连续性 5/14。它的应收与坏账 13/14,看起来很好,但这是因为平台替它收款;平台一旦下架或改变结算,应收科目仍然是零,收入却归零。买方在 8.2 里要确认的不是「有没有应收」,而是「Steam 账号、商店页、评价与结算关系能不能一起转」。如果转不了,191.8% 的缺口就只能折价。

Nord 有两组并列最弱。IP 与渠道 6/14 更低,所以先映射到 6.3 技术与知识产权尽调:咨询交付物归客户、产品归工作室,但转介绍 55% 没有合同,前 3 家客户 48%,买方会追问「客户关系是公司的还是合伙人的」。应收与坏账 7/14 映射到 6.1 财务尽调:Net 30、8% 逾期、2% 准备会进入营运资金调整。两组一起看,才能解释为什么 Nord 只能按 3.0 倍 SDE 成交,而不是 4.5 倍。

三张映射表合起来说明一件事:卷二末的最弱组,决定卷三的阅读起点。LedgerLite 和 Tidecast 从第 8 章读起,Nord 从第 6 章读起。不是所有人都要从第 1 章融资选项开始。

写成代码:volume-review.ts

代码把六组评分、评级和最弱组的路由写成函数。reviewRiskVolume 要求恰好六组,并且每组必须使用附录 C 的固定权重 20/16/14/14/14/14:少一组或改权重都报错,而不是按零分算——缺组意味着评审不完整,不是这一组没有风险。评级沿用 70% 和 55% 两条线,和卷一保持同一把尺子,跨卷比较不用重新换算。

最弱组按得分率排序,不按绝对失分排序。合同结构满分 20,丢 5 分是 75%;依赖与连续性满分 14,丢 3 分是 78.6%;绝对失分不同,得分率才说明相对缺口。分数相同时取后一组:LedgerLite 的 IP 与渠道、依赖与连续性都是 11/14,附录 C 把第六组设为交叉校验组,所以平局归连续性。

volumeThreeFocus 把六组映射到卷三的章节,返回章节号、节名和一句理由。依赖与连续性映射到第 8 章 8.2,而不是第 2 章的合伙人退出:这两家的依赖是云、支付和平台账号,不是合伙人;只有 Nord 的合伙人问题走第 2 章,而它当前的最弱组是 IP 与渠道,先走第 6 章。

// file: src/contract/volume-review.ts
// tier: L1
// verify: node --test test/contract/volume-review.test.ts

import { type Bps, divide } from "../core/rate.ts";
import { type Result, fail, ok } from "../core/result.ts";

export type RiskGroupKey =
  | "contract"
  | "keyTerms"
  | "receivable"
  | "disputeInsurance"
  | "ipChannel"
  | "continuity";

export type RiskReviewGroup = {
  key: RiskGroupKey;
  maxScore: number;
  score: number;
};

export type VolumeThreeFocus = {
  chapter: number;
  section: string;
  reason: string;
};

export type RiskReviewResult = {
  totalScore: number;
  maxScore: number;
  scoreBps: Bps;
  grade: "healthy" | "watch" | "high-risk";
  weakestKey: RiskGroupKey;
  weakestBps: Bps;
  focus: VolumeThreeFocus;
};

export const GROUP_ORDER: RiskGroupKey[] = [
  "contract",
  "keyTerms",
  "receivable",
  "disputeInsurance",
  "ipChannel",
  "continuity",
];

export const GROUP_LABELS: Record<RiskGroupKey, string> = {
  contract: "合同结构",
  keyTerms: "关键条款",
  receivable: "应收与坏账",
  disputeInsurance: "争议与保险",
  ipChannel: "IP 与渠道",
  continuity: "依赖与连续性",
};

/** Weights come from appendix C: 20 + 16 + 14 + 14 + 14 + 14 = 92. */
export const GROUP_MAX: Record<RiskGroupKey, number> = {
  contract: 20,
  keyTerms: 16,
  receivable: 14,
  disputeInsurance: 14,
  ipChannel: 14,
  continuity: 14,
};

/**
 * Each group points at the volume-three section where its gap gets priced.
 * The continuity group routes to closing and transition, because account and
 * contract migration is where dependency gaps become closing conditions.
 */
const FOCUS: Record<RiskGroupKey, VolumeThreeFocus> = {
  contract: {
    chapter: 6,
    section: "6.2 客户与合同尽调",
    reason: "合同能否转让、控制权变更是否触发终止,决定买方买到的收入是否延续",
  },
  keyTerms: {
    chapter: 7,
    section: "7.3 陈述保证、赔偿与托管",
    reason: "责任上限、SLA 与终止结算的缺口,要进入陈述保证与赔偿条款",
  },
  receivable: {
    chapter: 6,
    section: "6.1 财务尽调",
    reason: "应收账龄、坏账准备与营运资金调整,决定成交价的下调项",
  },
  disputeInsurance: {
    chapter: 7,
    section: "7.3 陈述保证、赔偿与托管",
    reason: "未决争议与未覆盖缺口,要在交割前转成托管或赔偿上限",
  },
  ipChannel: {
    chapter: 6,
    section: "6.3 技术与知识产权尽调",
    reason: "IP 归属、授权链与渠道集中度,决定资产能否干净地交割",
  },
  continuity: {
    chapter: 8,
    section: "8.2 客户、合同与账号迁移",
    reason: "云、支付与平台账号的迁移能力,决定交割后收入能不能连续",
  },
};

function isGroupKey(value: string): value is RiskGroupKey {
  return (GROUP_ORDER as string[]).includes(value);
}

/**
 * Scores the six fixed groups. All six must be present and each must use its
 * appendix C weight; a missing group or a reweighted group is a broken
 * review, not a zero score. Grades use the same 70% and 55% lines as volume
 * one so the two volumes can be compared without rescaling.
 */
export function reviewRiskVolume(
  groups: RiskReviewGroup[],
): Result<RiskReviewResult> {
  if (groups.length !== GROUP_ORDER.length) {
    return fail(`expected ${GROUP_ORDER.length} groups, got ${groups.length}`);
  }

  const seen = new Set<RiskGroupKey>();
  let totalScore = 0;
  let maxScore = 0;
  let weakestKey: RiskGroupKey = GROUP_ORDER[0];
  let weakestBps: Bps = 10001;

  for (const group of groups) {
    if (!isGroupKey(group.key)) {
      return fail(`unknown group ${group.key}`);
    }
    if (seen.has(group.key)) {
      return fail(`duplicate group ${group.key}`);
    }
    seen.add(group.key);
    if (group.maxScore !== GROUP_MAX[group.key]) {
      return fail(`group ${group.key} must use weight ${GROUP_MAX[group.key]}`);
    }
    if (
      !Number.isInteger(group.score) ||
      group.score < 0 ||
      group.score > group.maxScore
    ) {
      return fail(`group ${group.key} score must be between 0 and its max`);
    }
    totalScore += group.score;
    maxScore += group.maxScore;
    const groupBps = divide(group.score, group.maxScore);
    // Ties go to the later group: continuity is appendix C's cross-check
    // group, so a tie with IP and channel should still surface as continuity.
    if (groupBps <= weakestBps) {
      weakestKey = group.key;
      weakestBps = groupBps;
    }
  }

  for (const key of GROUP_ORDER) {
    if (!seen.has(key)) {
      return fail(`missing group ${key}`);
    }
  }

  const scoreBps = divide(totalScore, maxScore);
  const grade: RiskReviewResult["grade"] =
    scoreBps >= 7000 ? "healthy" : scoreBps >= 5500 ? "watch" : "high-risk";

  return ok({
    totalScore,
    maxScore,
    scoreBps,
    grade,
    weakestKey,
    weakestBps,
    focus: FOCUS[weakestKey],
  });
}

/** Returns the volume-three routing target for a single group. */
export function volumeThreeFocus(key: RiskGroupKey): VolumeThreeFocus | null {
  return FOCUS[key] ?? null;
}

把三案例代进去,结果是 LedgerLite 78 分、健康、最弱依赖与连续性、路由到卷三第 8 章;Tidecast 62 分、需关注、最弱依赖与连续性、路由到第 8 章;Nord 50 分、高风险、最弱 IP 与渠道、路由到第 6 章。代码给出的 weakestBps 分别是 7,857、3,571、4,286,和正文的百分比一致。

代码不判断分数是否「够好」,也不判断卷三的章节是否真的适合你的生意。它只保证三件事:六组必须齐全、权重必须固定、最弱组必须有路由。剩下的判断留给读者,因为评分是工具,不是结论。

进入卷三前的三个动作

第一个动作:把 13.1 的矩阵升级成「可转让版本」。原矩阵的八列回答「条款值多少钱」,升级版要再加四列:控制权变更是否触发终止、合同转让是否需要对方同意、终止后卖方是否提供过渡支持、依赖账号能否迁移。四列都是「是/否/不清楚」,不清楚按否处理。LedgerLite 的 260 份订阅合同里,如果有一份写了控制权变更条款,买方就会要求逐份确认;Tidecast 的 Steam 账号与商店页能不能转,直接决定 8.2 的交割清单;Nord 的咨询合同大多按项目签,转让相对容易,但客户关系跟人走。这个动作的成本是几个小时,收益是尽调时少一轮追问。

第二个动作:把 13.2 的敞口表做成季度基线。一张表只需要五列:应收余额、逾期比例、坏账准备、风险期望损失、未覆盖缺口;再加两个比率:缺口 ÷ SDE、保额 ÷ 单次最大损失。每季度用同一个口径填一次,连续四个季度后,趋势比单点数字更有信息。LedgerLite 的缺口从 $13,337 涨到 $20,000,可能是保额没跟上收入,也可能是免赔额变了;Tidecast 的缺口从 $232,430 降到 $150,000,可能是 Steam 占比降了,也可能是授权保底重谈了。没有基线,这两种变化都看不出来。

第三个动作:用附录 C 打一次分,把最弱的一组写成一页「卷三入场任务」。一页纸四行:最弱的组、对应卷三章节、需要补的证据、负责人和截止日。不要一次修六组;先修最弱的一组,再修与它联动的那一组。Nord 的最弱组是 IP 与渠道 6/14,联动的是应收与坏账 7/14;两组一起修,才能把「客户关系是公司的还是合伙人的」这个问题回答清楚。LedgerLite 和 Tidecast 的最弱组都是依赖与连续性,联动的是合同结构里的转让条款;账号迁移和合同转让要一起谈。

三个动作做完,卷三的第一节不会从估值倍数开始,而会从「你的生意能不能被交割」开始。估值是结果,交割能力是前提。

三个交接问题

从卷二进入卷三,有三个问题必须先回答。它们不属于合同正文,但决定了卷三哪些章节对你最重要。

第一,融资结构:你需要外部资本吗? 如果需要,稀释多少、治理权让多少、投资人信息权到哪一步?LedgerLite 的 3.2× ARR = $768,768 是收购锚,不是融资锚;它现在的现金流不需要外部资本,融资只会增加退出时的清算优先权。Tidecast 和 Nord 的现金流更薄,但融资的代价也更高:一个依赖平台,一个依赖合伙人,投资人会要求更强的保护条款。卷三第 1 章会把自力更生、借款、股权融资三条路的代价算清楚。

第二,退出路径:这门生意卖给谁? LedgerLite 走战略买方,价格 3.2× ARR = $768,768,结构是现金 70%($538,138)+ earn-out 30%($230,630,12 个月,ARR ≥95% 全额),另有 10% 托管 $76,877。Tidecast 有两条路:IP 授权 3 年,保底 $60,000/年 + 8% 净收入,最低保证 $180,000;或者整体出售 1.8× 收入 = $248,708。Nord 也有两条:一位合伙人退出,买断 50% × 4.5 × SDE = $77,220,分 24 个月;或者整体被并购,3.0× SDE = $102,960。路径不同,卷二哪些条款最重要也不同:A 看账号迁移与托管,B 看平台账号与不得转授权,C 看 IP 归属与客户关系。

第三,交割条件:买方会在交割前要求什么? 哪些合同需要对方同意才能转让?控制权变更会不会触发终止?托管和 earn-out 怎么设?LedgerLite 的营运资金调整已经出现:目标 $15,000、实际 $12,000,下调 $3,000;Tidecast 的音乐授权不得转授权,Steam 账号与商店页要逐项确认;Nord 的合伙人买断分 24 个月,交割前必须先把这份协议写成书面文件,并把交付物归属列成清单。三个问题的答案,会直接变成卷三第 6 章尽调、第 7 章结构、第 8 章交割的检查项。

三个问题没有标准答案,但每个答案都能回到卷二的一张表:融资结构回到现金流与缺口,退出路径回到估值锚与合同终止条款,交割条件回到矩阵的可转让列与依赖账号清单。把这三张表放在手边,卷三就不是一本新书,而是卷二的自然延续。

小结

  • 卷二用附录 C 的六组清单收口:合同结构 20 分、关键条款 16 分、应收与坏账 14 分、争议与保险 14 分、IP 与渠道 14 分、依赖与连续性 14 分,合计 92 分。
  • 三案例得分:LedgerLite 78(84.8%,健康)、Tidecast 62(67.4%,需关注)、Nord Studio 50(54.3%,高风险)。
  • LedgerLite 的最弱组是依赖与连续性(11/14),云与支付账号迁移会进入卷三第 8 章 8.2 的交割条件。
  • Tidecast 的最弱组也是依赖与连续性(5/14),Steam 账号、商店页与结算关系决定收入能否延续。
  • Nord 的最弱组是 IP 与渠道(6/14),其次是应收与坏账(7/14);分别进入卷三 6.3 与 6.1。
  • 进入卷三前的三个动作:矩阵加可转让四列、敞口做成季度基线、用附录 C 打分并写一页入场任务。
  • 三个交接问题:融资结构、退出路径、交割条件;每个答案都能回到卷二的一张表。
  • 分数不是估值;它只衡量合同与风险能不能被第三方复核,估值还看增长、市场与买方战略。

阅读导航:上一节:13.2 应收与风险敞口 · 下一节:目录与学习路径 。

常见错误与边界

  1. 把分数当估值。 78 分不代表能按 3.2× ARR 成交;评分衡量可复核性,估值还看增长、市场与买方战略。
  2. 只修高分项。 高分项再修也加不了几分,最弱组才是折价来源;LedgerLite 的依赖与连续性只丢 3 分,但账号迁移会卡交割。
  3. 缺一组按零分算。 缺组是评审不完整,不是这一组没有风险;代码直接报错,正文也不给补零。
  4. 按绝对失分选最弱组。 满分不同,失分不可直接比;合同结构满分 20,依赖与连续性满分 14,要用得分率。
  5. 把「不适用」当满分。 Tidecast 没有保险,不代表争议与保险组满分;没有替代证据就给 0 或 1。
  6. 三个动作同时做。 矩阵、敞口、评分一起动,流程会乱;先做敞口基线,再做矩阵升级,最后评分。
  7. 把最弱组当成「要修的组」。 最弱组是「会被定价的组」;修它在卷二,定价它在卷三,两个动作不能混。
  8. 忽略交接问题的顺序。 先答融资结构,再答退出路径,最后答交割条件;顺序反了,会把融资当成退出的替代。
  9. 把卷三当成独立的一本书。 卷三的估值、尽调、结构、交割都建立在卷二的三张表上;表不在,章节就只是概念。
  10. 分数不动就以为没问题。 分数不动但结构在恶化——缺口占 SDE 上升、最弱组换人——同样要处理。

本节的边界是「卷二评审与卷三交接」:只覆盖附录 C 的六组评分、最弱组路由、三个动作和三个交接问题,不展开卷三的估值方法、交易结构与交割清单。所有分数和阈值都是教学示例;正式交易中的评审与尽调应由专业人员完成。合同条款的财务后果见 13.1 合同条款矩阵 ,应收与缺口的横向对照见 13.2 应收与风险敞口 ,保险与缺口的联动见 12.3 保险、备份与应急预案的联动 。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「books」更多文章

  1. 《移动游戏产品的架构·商业化与发行工程》附录 C 商业化与发行评审清单
  2. 《移动游戏产品的架构·商业化与发行工程》附录 B 双案例商业化事实表
  3. 《移动游戏产品的架构·商业化与发行工程》附录 A 商业化与发行术语速查