以下情境为教学假设,人物与数字不代表经核实的真实案例。
买保险的人常犯一个错:把保单当成「出事就赔」的开关。真出事时才发现,保单有免赔额、有除外责任、有单次限额和年度总限额;备份也一样,能恢复数据,但不能恢复客户;应急预案能缩短停机,但不能把损失降到零。三者不是三选一,而是三层覆盖,各管一段。
这一节把三层放在同一张表上,用「覆盖倍数 = 保障额度 ÷ 单次最大损失」和「缺口 = 最大损失 − 实际覆盖」两个数,判断哪些风险已经转移、哪些只是减损、哪些还完全敞着。最后用一个可承受阈值,把「已知」和「可承受」分开。
三层覆盖:各管一段
| 层 | 作用 | 覆盖什么 | 不覆盖什么 | 现金口径 |
|---|---|---|---|---|
| 保险 | 转移财务损失 | 责任赔偿、响应费用、部分营业中断 | 免赔额、除外责任、未投保风险 | 保障额度 ÷ 单次最大损失 |
| 备份 | 降低损失 | 数据、配置、构建产物 | 收入中断、客户流失、法律责任 | 恢复比例 × 最大损失 |
| 预案 | 缩短停机与降低概率 | 替代流程、责任人、触发条件 | 无法消除的损失 | 最大损失 − 恢复 − 保险 |
| 无 | 自留 | 无 | 全部 | 缺口 = 最大损失 |
三层的关系是「先减损,再转移,最后自留」。备份和预案先把损失压小,保险再对剩余损失赔付,剩下的免赔额和除外责任由自己承担。顺序不能反:如果先让保险赔,再让备份恢复,保险人会要求扣除已经恢复的部分;如果先有预案缩短停机,营业中断的赔付也会相应减少。
保险的核心数是覆盖倍数。它不是「保单金额越大越好」,而是「保障额度能不能覆盖一次事件的合理上限」。覆盖倍数小于 1,说明保额不够;大于 1,说明保额够,但不等于没有缺口——免赔额、除外责任和年度总限额仍然会留下自留部分。
备份的核心数是恢复比例。它不是「有没有备份」,而是「备份能恢复多少、要多久」。每天备份一次,RPO 是 24 小时;恢复要 8 小时,RTO 是 8 小时。备份能降低数据损失,但不能降低收入中断,也不能降低法律责任。
预案的核心数是剩余缺口。它不是「有没有写」,而是「写了之后,最坏情况还剩多少」。预案可以缩短停机、降低概率、提供替代路径,但它不能把损失变成零;它的价值是把「不可承受」压到「可承受」。
LedgerLite:$1M 网络安全险够不够
LedgerLite 的网络安全险保额是 $1,000,000。要判断够不够,先算单次最大损失。这里取三个部分:
- 责任赔偿上限:公司层面 12 个月费用 $240,240;
- 泄露响应成本:年收入的 15%,即 $36,036(教学假设);
- 7 天营业中断(教学假设):MRR $20,020 × 7 ÷ 30 = $4,671。
三项相加,单次最大损失是 $240,240 + $36,036 + $4,671 = $280,947。
保单有 $10,000 的免赔额(教学假设)。覆盖倍数是:
覆盖倍数 = 1,000,000 ÷ 280,947 = 3.56
实际赔付 = 280,947 − 10,000 = 270,947
缺口 = 280,947 − 270,947 = 10,000
3.56 倍看起来绰绰有余,但缺口不是零:$10,000 的免赔额要自己承担。更重要的是,保单不覆盖所有事。LedgerLite 的云中断不在网络安全险的责任范围内;一周停机(教学假设)的损失约 $6,674,备份和预案能恢复 50%,剩余缺口 $3,337。这里的 $6,674 是现金影响,包含 SLA 抵扣;12.1 的登记册只算收入损失 $4,671,所以两个数字不同,口径也不同。把两块缺口加起来,LedgerLite 的总缺口是 $10,000 + $3,337 = $13,337,占 SDE $130,240 的 10.2%。
这个比例低于本节设定的 50% 可承受阈值(教学假设),所以 LedgerLite 的风险是「已知且可承受」的。注意,这不是说 LedgerLite 不会出事,而是说出事之后,最坏情况的自留部分在一年 SDE 的 10.2% 以内,不需要动用权益或借债。
还要检查保单的年度总限额。覆盖倍数是按单次事件算的;如果保单的年度总限额也是 $1M,一年内两次 $280,947 的事件就会把限额用掉 56.2%,第三次就没有保障了。案例只给了一个保额数字,没有给年度总限额;实际签约时要问清楚「单次限额」和「年度总限额」是不是同一个数。
Tidecast:没有保险的两种缺口
Tidecast 没有保险。它的两个主要风险都只能靠预案,缺口是全额减去预案能恢复的部分。
第一个是 IP 侵权。Tidecast 的音乐是买断授权,不得转授权;IP 授权报价是保底 $60,000/年 + 8% 净收入,3 年最低保证 $180,000。如果侵权导致授权终止,最坏情况是三年的最低保证全部落空,单次最大损失取 $180,000。12.1 的登记册按一年保底 $60,000 计期望损失;这里做覆盖测试,取三年最低保证 $180,000,因为一次侵权可能让整份授权终止。预案能做什么?授权链条审计、清权记录、替换曲库。教学假设预案能恢复 20%,剩余缺口是 $180,000 × 80% = $144,000。
第二个是 Steam 下架。Steam 占净收入的 80%,全年 $110,537。如果 Steam 下架,官网直售只能接住一部分;教学假设预案能恢复 20%,剩余缺口是 $110,537 × 80% = $88,430。
两块缺口合计 $144,000 + $88,430 = $232,430,占 SDE $121,171 的 191.8%。这个数字远超 50% 的可承受阈值。Tidecast 的风险是「已知」的,但不是「可承受」的;它需要转移或回避,而不是继续写预案。
量化的路径有三条:
- 买 IP 保险。假设 $180,000 保额、年保费 $4,500(教学假设),IP 缺口从 $144,000 降到免赔额(假设 $5,000),总缺口变成 $5,000 + $88,430 = $93,430,占 SDE 77.1%。
- 降低 Steam 占比。如果 Steam 从 80% 降到 60%,Steam 最大损失从 $110,537 降到 $82,903;按 20% 恢复,缺口 $66,322;加上 IP 保险后的 $5,000,总缺口 $71,322,占 SDE 58.9%。
- 继续降到 50%。Steam 最大损失 $69,086,缺口 $55,269;加上 $5,000,总缺口 $60,269,占 SDE 49.7%,刚好低于 50%。
所以 Tidecast 的「可承受」不是一句态度,而是一组动作:IP 保险 + Steam 占比降到 50%。这两个动作都可以量化,也都可以写进下一年的预算。
Nord:E&O 覆盖专业责任,但不覆盖集中度
Nord 有 $500,000 的 E&O 保险。E&O 覆盖专业责任:咨询交付出错、建议失误、交付物缺陷导致的客户索赔。它不覆盖关键人依赖,也不覆盖客户集中。
先算专业责任的单次最大损失。Nord 的咨询年收入是 $112,200;如果一个大客户因为交付问题要求退还全年咨询费,再加上 $24,000 的重做成本(教学假设取直接成本),单次最大损失是 $136,200。E&O 保额 $500,000,免赔额 $10,000(教学假设,与第 6.2 节一致):
覆盖倍数 = 500,000 ÷ 136,200 = 3.67
实际赔付 = 136,200 − 10,000 = 126,200
缺口 = 10,000
3.67 倍,缺口只有 $10,000。专业责任这一块,Nord 的覆盖是够的。
但 Nord 的两个更大缺口不在 E&O 里。
关键人依赖:一位合伙人缺席 6 个月,咨询收入减半,损失 $28,050。备份(文档化、客户交接清单)能恢复 40%,剩余缺口 $16,830。E&O 不赔「合伙人不能工作」,因为这不是专业责任,而是经营中断。
单一大额应收:年末应收中的单笔大额 $11,264。预案(信用额度、催收流程)能恢复 50%,剩余缺口 $5,632。E&O 不赔客户不付钱,因为这不是专业责任,而是信用风险。
Nord 的总缺口是 $5,000 + $16,830 + $5,632 = $27,462,占 SDE $34,320 的 80.0%,超过 50% 阈值。Nord 的风险也是「已知」但「不可承受」的。
要把 Nord 压到 50% 以下,缺口必须降到 $17,160 以内。可选的工具不是 E&O,而是另外两类:关键人保险(覆盖合伙人缺席)和信用保险(覆盖应收坏账)。如果关键人保险覆盖 $28,050、信用保险覆盖 $5,632,总缺口只剩 E&O 的 $5,000,占 SDE 14.6%。这就是「保险要按风险类型买」的意思:E&O 再好,也赔不了关键人和应收。
覆盖倍数与缺口:一张表
把三家的七条风险放进同一张表,按「最大损失 − 恢复 − 保险赔付」算缺口:
| 案例 | 风险 | 层 | 单次最大损失 | 保障额度 | 覆盖倍数 | 缺口 |
|---|---|---|---|---|---|---|
| LedgerLite | 数据泄露 | 保险 | $280,947 | $1,000,000 | 3.56× | $10,000 |
| LedgerLite | 云中断 | 备份 + 预案 | $6,674 | $0 | 0 | $3,337 |
| Tidecast | IP 侵权 | 预案 | $180,000 | $0 | 0 | $144,000 |
| Tidecast | Steam 下架 | 预案 | $110,537 | $0 | 0 | $88,430 |
| Nord | 关键人依赖 | 备份 + 预案 | $28,050 | $0 | 0 | $16,830 |
| Nord | 专业责任 | 保险 | $136,200 | $500,000 | 3.67× | $5,000 |
| Nord | 单一大额应收 | 预案 | $11,264 | $0 | 0 | $5,632 |
| 合计 | $753,672 | $273,229 |
这张表最重要的不是合计,而是结构:七条风险里只有两条有保险,两条的覆盖倍数都大于 3;另外五条只有备份或预案,缺口合计 $258,229,占全部缺口的 94.5%。保险覆盖的是「低频高损、有明确责任方」的风险;备份和预案覆盖的是「高频、责任分散、保险不赔」的风险。两者不能互相替代。
按案例汇总缺口占 SDE 的比例:
| 案例 | 缺口合计 | SDE | 占 SDE | 判断 |
|---|---|---|---|---|
| LedgerLite | $13,337 | $130,240 | 10.2% | 已知且可承受 |
| Tidecast | $232,430 | $121,171 | 191.8% | 已知但不可承受 |
| Nord | $27,462 | $34,320 | 80.0% | 已知但不可承受 |
50% 这个阈值是教学假设,不是行业标准。它的作用是给「可承受」一个可比较的定义:缺口不超过半年 SDE,说明一次最坏事件不会把当年的 owner earnings 全部吃掉;超过 50%,就需要在保险、备份、预案或业务结构上做调整。
这就是「风险敞口不是零,而是已知且可承受」的完整含义。敞口不是零:LedgerLite 还有 $13,337 的自留,Tidecast 还有 $232,430,Nord 还有 $27,462。已知:每一笔都能从案例数字复算,都有责任人和缓解措施。可承受:只有 LedgerLite 当前达标;Tidecast 和 Nord 的缺口还是「已知但不可承受」,它们的动作清单就是下一年的预算项。把「已知」变成「可承受」,才是这一节和下一章的分界。
写成代码:continuity-link.ts
下面的 continuity-link.ts 先算恢复,再算保险,最后算缺口。coverRisk 的顺序是:recoveryBps 先把最大损失压成净损失,保险再对净损失赔付,赔付上限是保额,扣除免赔额;gapCents 是净损失减去实际赔付。limitMultipleBps 用毛损失做分母,因为覆盖倍数回答的是「保额够不够覆盖事件本身」,不是「赔付后还剩多少」。
// file: src/contract/continuity-link.ts
// tier: L1
// verify: node --test test/contract/continuity-link.test.ts
import { type Cents } from "../core/money.ts";
import { type Bps, applyRate, divide } from "../core/rate.ts";
import { type Result, fail, ok } from "../core/result.ts";
export type ContinuityLayer = "insurance" | "backup" | "plan" | "none";
export type RiskCover = {
name: string;
layer: ContinuityLayer;
maxLossCents: Cents;
limitCents: Cents;
deductibleCents: Cents;
recoveryBps: Bps;
};
export type CoverRow = {
name: string;
layer: ContinuityLayer;
maxLossCents: Cents;
limitCents: Cents;
deductibleCents: Cents;
recoveryCents: Cents;
netLossCents: Cents;
coveredCents: Cents;
gapCents: Cents;
limitMultipleBps: Bps;
};
export type CoverSummary = {
rows: CoverRow[];
totalMaxLossCents: Cents;
totalGapCents: Cents;
worstGapName: string;
worstGapCents: Cents;
};
function validAmount(value: Cents): boolean {
return Number.isInteger(value) && value >= 0;
}
function validRate(value: Bps): boolean {
return Number.isInteger(value) && value >= 0 && value <= 10000;
}
function isLayer(value: string): value is ContinuityLayer {
return (
value === "insurance" ||
value === "backup" ||
value === "plan" ||
value === "none"
);
}
/**
* A loss is first reduced by backup or plan recovery, then paid by insurance
* up to the limit, minus the deductible. The gap is what remains after both
* layers. The limit multiple uses the gross loss, not the net loss, because
* the question is whether the policy is large enough for the event itself.
*/
export function coverRisk(input: RiskCover): Result<CoverRow> {
if (input.name.trim() === "") {
return fail("risk name cannot be empty");
}
if (!isLayer(input.layer)) {
return fail("layer must be insurance, backup, plan or none");
}
if (
!validAmount(input.maxLossCents) ||
!validAmount(input.limitCents) ||
!validAmount(input.deductibleCents)
) {
return fail("amounts must be non-negative integers in cents");
}
if (!validRate(input.recoveryBps)) {
return fail("recovery must be between 0 and 10000 bps");
}
if (input.maxLossCents === 0) {
return fail("max loss must be greater than zero");
}
const recoveryCents = applyRate(input.maxLossCents, input.recoveryBps);
const netLossCents = input.maxLossCents - recoveryCents;
const coveredCents = Math.max(
0,
Math.min(netLossCents, input.limitCents) - input.deductibleCents,
);
const gapCents = netLossCents - coveredCents;
return ok({
name: input.name,
layer: input.layer,
maxLossCents: input.maxLossCents,
limitCents: input.limitCents,
deductibleCents: input.deductibleCents,
recoveryCents,
netLossCents,
coveredCents,
gapCents,
limitMultipleBps: divide(input.limitCents, input.maxLossCents),
});
}
/**
* The summary sums the gaps and names the largest one. A gap is not a failure
* by itself; it is only a failure when it cannot be absorbed by SDE. The
* caller supplies that test in the chapter, not in this function.
*/
export function summarizeCover(risks: RiskCover[]): Result<CoverSummary> {
const rows: CoverRow[] = [];
for (const risk of risks) {
const row = coverRisk(risk);
if (!row.ok) {
return row;
}
rows.push(row.value);
}
const totalMaxLossCents = rows.reduce(
(acc, row) => acc + row.maxLossCents,
0,
);
const totalGapCents = rows.reduce((acc, row) => acc + row.gapCents, 0);
let worstGapName = "";
let worstGapCents = -1;
for (const row of rows) {
if (row.gapCents > worstGapCents) {
worstGapName = row.name;
worstGapCents = row.gapCents;
}
}
return ok({
rows,
totalMaxLossCents,
totalGapCents,
worstGapName,
worstGapCents: worstGapCents < 0 ? 0 : worstGapCents,
});
}
把七条风险换成美分代进去:
- LedgerLite 数据泄露:最大损失 28,094,700 美分,保额 100,000,000 美分,免赔 1,000,000 美分,恢复 0。覆盖倍数 35,594 bps(3.56×),实际赔付 27,094,700 美分($270,947),缺口 1,000,000 美分($10,000)。
- LedgerLite 云中断:最大损失 667,400 美分,无保险,恢复 5,000 bps(50%)。净损失 333,700 美分($3,337),缺口同额。
- Tidecast IP 侵权:最大损失 18,000,000 美分,无保险,恢复 2,000 bps(20%)。净损失 14,400,000 美分($144,000),缺口同额。
- Tidecast Steam 下架:最大损失 11,053,700 美分,无保险,恢复 2,000 bps。净损失 8,842,960 美分($88,429.60),缺口同额。
- Nord 关键人依赖:最大损失 2,805,000 美分,无保险,恢复 4,000 bps(40%)。净损失 1,683,000 美分($16,830),缺口同额。
- Nord 专业责任:最大损失 13,620,000 美分,保额 50,000,000 美分,免赔 500,000 美分,恢复 0。覆盖倍数 36,711 bps(3.67×),赔付 13,120,000 美分($131,200),缺口 500,000 美分($5,000)。
- Nord 单一大额应收:最大损失 1,126,400 美分,无保险,恢复 5,000 bps(50%)。净损失 563,200 美分($5,632),缺口同额。
汇总结果是总最大损失 75,367,200 美分($753,672),总缺口 27,322,860 美分($273,228.60),最大缺口是 Tidecast 的 IP 侵权,14,400,000 美分($144,000)。
代码只算「一次事件」的覆盖与缺口,不处理年度总限额、多次事件叠加和保险拒赔。它也不判断 50% 阈值是否适合你的生意;阈值是管理判断,不是代码逻辑。代码的用处是让每一笔缺口都能复算,避免「有保险就放心」和「没保险就绝望」这两种极端。
小结
- 保险、备份、预案是三层覆盖:保险赔钱,备份减损,预案缩短停机;三者不能互相替代。
- 覆盖倍数 = 保障额度 ÷ 单次最大损失;LedgerLite 的数据泄露是 3.56×,Nord 的专业责任是 3.67×。
- 覆盖倍数大于 1 不等于没有缺口;免赔额、除外责任和年度总限额仍然留下自留部分。
- LedgerLite 的单次最大损失 $280,947,保额 $1M,缺口 $10,000;加上云中断缺口 $3,337,总缺口 $13,337,占 SDE 10.2%。
- Tidecast 没有保险,IP 缺口 $144,000、Steam 缺口 $88,430,合计 $232,430,占 SDE 191.8%;需要 IP 保险 + Steam 占比降到 50% 才能低于阈值。
- Nord 的 E&O 覆盖专业责任(缺口 $5,000),但不覆盖关键人($16,830)和应收($5,632);总缺口 $27,462,占 SDE 80.0%。
- 七条风险里只有两条有保险,保险覆盖的是低频高损、责任明确的风险;其余五条靠备份和预案。
- 50% 阈值是教学假设;按这个口径,只有 LedgerLite 当前「已知且可承受」,Tidecast 和 Nord 还需要补缺口。
- 风险敞口不是零,而是已知且可承受;「已知」靠这张表,「可承受」靠缺口占 SDE 的比例。
阅读导航:上一节:12.2 业务连续性计划 · 下一节:13.1 三案例合同矩阵 。
常见错误与边界
- 把保险当成「出事就赔」。 免赔额、除外责任、单次限额和年度总限额都会留下缺口;保单不是开关。
- 只看保额不看覆盖倍数。 $1M 的保额对 $280,947 的损失是 3.56×,对 $2M 的损失只有 0.5×;保额要和单次最大损失比。
- 覆盖倍数大于 1 就认为没有缺口。 LedgerLite 的 3.56× 仍然留下 $10,000 免赔额;倍数和缺口要一起看。
- 用备份替代保险。 备份能恢复数据,不能赔客户索赔;两者管的是不同的损失。
- 用保险替代备份。 保险赔钱,但不能恢复服务;停机期间客户流失,保险不赔。
- 用预案替代保险。 预案能缩短停机,但不能把 IP 侵权或平台下架的损失变成零;Tidecast 的缺口就是例子。
- 把 E&O 当成万能险。 E&O 只覆盖专业责任,不覆盖关键人、应收坏账和客户集中;Nord 的两个大缺口都不在 E&O 里。
- 忽略年度总限额。 覆盖倍数是按单次事件算的;一年多次事件会共享年度限额,第三次可能没有保障。
- 用毛损失算缺口。 缺口要减掉恢复和实际赔付;用毛损失会高估缺口,用保额会低估缺口。
- 把 50% 阈值当成行业标准。 它是教学假设;你的阈值取决于现金储备、融资能力和风险偏好。
本节的边界是「一次事件的保险、备份、预案覆盖与缺口」:只覆盖三层覆盖、覆盖倍数、缺口和占 SDE 的比例,不展开保单条款解释、理赔流程和保险定价。所有保额、免赔额、恢复比例和 50% 阈值都是教学假设;具体保单以合同为准,本节不构成保险或法律意见。风险的期望损失与排序见 12.1 风险登记册:概率、影响、责任人 ;停机损失与冗余回本点见 12.2 业务连续性计划 。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。