站内《上线变现与长线运营》 已经把渠道机制与素材设计框架、eCPM/LTV/定价/留存/AB 实验这些「赚多少」的模型写完;那 51 篇是方法论与建模口径。本卷不重做这些,只做投放后台实操、广告聚合 SDK 对接、移动归因、资质办理、渠道联运与结算这些「钱怎么花出去、怎么收回来」的落地环节。到了收官这一章,任务变成一件很朴素的事:把前面 15 章各自的交付物装订成一册能交给操盘手直接用的手册。书架索引见全部书稿 ,那只是入口;手册是把散落的配置、清单与口径按章号钉在一起的成品。
手册不是把 15 份文档拼起来
一份能用的操盘手册,光有目录不够,光有正文也不够。它至少要把三样东西对齐到同一套章号上:
| 组成 | 作用 | 缺了会怎样 |
|---|---|---|
| 目录 | 按章号索引到交付物与配置 | 找不到「第 9 章的渠道分级表在哪」 |
| 验收清单 | 每章一条可核对的合格标准 | 交付了但没人知道算不算完成 |
| 配置汇总 | 每章登记的配置文件来源 | 配置散落各处,改了 A 忘了 B |
三样东西必须共用同一套章号与同一份清单文件,否则手册会在第一次更新时就散架:有人加了第 12 章的配置却忘了在目录里登记,有人删了清单项却没人发现。所以本节的做法不是「写一本手册」,而是写一份手册的装配清单,再用一段程序校验它自洽——清单是唯一真源,目录、检查项与配置来源都从它派生。
D 层:装配清单
下面这份是 D 层装配清单 config/o16_handbook.json。它把卷四 16 章各登记一行:章号、章标题、一份主交付物、一份配置来源、一条验收清单。第 15 章是案例复盘,交付物是文档而非配置,故 config 留空。
{
"version": 1,
"game": "merge-island",
"observedAt": "2026-10",
"title": "《合成小岛》商业运营操盘手册",
"note": "操盘手册的装配清单(D 层):把卷四第 1–15 章的交付物按章号装订成一册,每章登记一份主交付物、一份配置来源与一条验收清单。口径是「装配结构」的建模,不是任何真实交付物的实测。config 为空字符串表示该章交付物是复盘/案例文档而非配置(第 15 章)。真实交付物内容需真实业务环境,命令行不可复现(X)。全字段为整数或字符串,无浮点。",
"chapters": [
{ "ch": 1, "title": "投放后台与账户结构", "deliverable": "账户层级与出价配置表", "config": "o01_hierarchy.json", "check": "账户/计划/广告组/创意四级齐全,出价方式与预算分配已标注" },
{ "ch": 2, "title": "出价与放量", "deliverable": "出价选择与预算爬坡表", "config": "o02_bid_choice.json", "check": "oCPM/CPA/ROI 三选一有依据,爬坡节奏与止损线成对出现" },
{ "ch": 3, "title": "素材工业化", "deliverable": "素材生产线与测试矩阵", "config": "o03_line.json", "check": "素材编号可追溯,测试矩阵每格有判定阈值与淘汰规则" },
{ "ch": 4, "title": "移动归因", "deliverable": "归因窗口与三方对账表", "config": "o04_window.json", "check": "点击/展示归因窗口写明,三方差异有容差与追因路径" },
{ "ch": 5, "title": "广告聚合平台", "deliverable": "聚合架构与接入差异表", "config": "o05_mediation.json", "check": "穿山甲/优量汇/AdMob 接入差异逐项对照,瀑布流层级完整" },
{ "ch": 6, "title": "广告位配置与调优", "deliverable": "广告位 ID 与流量分组表", "config": "o06_adslot.json", "check": "广告位 ID 唯一,eCPM 分层与填充/展示率诊断口径一致" },
{ "ch": 7, "title": "内购与支付通道", "deliverable": "订单·回调·补单流程表", "config": "o07_pay_channel.json", "check": "订单状态机闭合,回调幂等与补单重试已定义" },
{ "ch": 8, "title": "变现合规", "deliverable": "广告内容与隐私合规清单", "config": "o08_adcopy.json", "check": "广告素材红线逐条可查,未成年人保护与同意管理有落点" },
{ "ch": 9, "title": "渠道与联运", "deliverable": "渠道分级与结算周期表", "config": "o09_channel_tier.json", "check": "渠道分档有对接清单,分成与结算周期逐渠道写明" },
{ "ch": 10, "title": "代理发行与商务", "deliverable": "自发行/代理决策与筹码表", "config": "o10_clauses.json", "check": "分成谈判筹码与底线量化,合同关键条款清单可核" },
{ "ch": 11, "title": "版号与资质办理", "deliverable": "申请材料与倒排时间线", "config": "o11_material.json", "check": "出版物号/文网文/软著材料齐全,资质倒排前置上线节点" },
{ "ch": 12, "title": "结算与财务", "deliverable": "平台分成与结算周期表", "config": "o12_settlement.json", "check": "扣点顺序正确,账期拆结算周期+冻结期,税务口径标 X" },
{ "ch": 13, "title": "运营机制与协作", "deliverable": "运营 SOP 与例会编排表", "config": "o13_sop.json", "check": "关键指标挂到例会节点,客服/社区分工边界已声明" },
{ "ch": 14, "title": "从投放到变现的完整账", "deliverable": "单位账与月度经营账", "config": "o14_unit.json", "check": "CAC/ARPDAU/LTV 口径一致,月度利润与现金流缺口可复算" },
{ "ch": 15, "title": "案例与失败模式", "deliverable": "《合成小岛》投放变现复盘", "config": "", "check": "失败模式有可跑对照脚本,关键决策对照表可追溯" },
{ "ch": 16, "title": "操盘收官", "deliverable": "操盘手册与全链路对账", "config": "o16_handbook.json", "check": "手册装配完整、全链路对账残差在容差内、交付物清单闭合" }
]
}
清单本身是数据,它是否自洽要靠程序判定:16 章齐不齐、章号重不重、三要素有没有空、登记的配置文件到底存不存在——这些都是可以机械检查的,不该靠人肉扫。
P 层:装配内核
下面这段是 P 层装配内核 core/src/o16/handbook.ts。它读同一份清单,逐条校验结构,并给出一枚清单指纹(对「章号|标题|交付物|配置|清单」逐行做 FNV-1a 32 位)。指纹的用处是:清单只要被人偷偷改一个字,指纹就变,交接时一比对就知道版本对不对。
// file: core/src/o16/handbook.ts
// tier: P
// verify: node --test 'core/test/o16_*.test.ts'
//
// 操盘手册装配内核:读 config/o16_handbook.json 的装配清单,校验「第 1–16 章齐全、章号唯一、
// 每章三要素(交付物/配置来源/验收清单)不缺、登记的配置确实存在」,并给出一枚清单指纹
// (FNV-1a 32 位,与 Python 侧同法可对拍)。只用可擦除语法(禁 enum / namespace / 参数属性 / 装饰器)。
export interface HandbookChapter {
readonly ch: number; readonly title: string;
readonly deliverable: string; readonly config: string; readonly check: string;
}
export interface Handbook {
readonly version: number; readonly game: string; readonly title: string;
readonly chapters: readonly HandbookChapter[];
}
export interface HandbookReport {
readonly chapterCount: number; readonly expected: number;
readonly missing: number[]; readonly dupChapters: number[]; readonly emptyFields: string[];
readonly missingConfigs: string[]; readonly configCount: number;
readonly fingerprint: string; readonly valid: boolean;
}
/** 清单指纹:对「章号|标题|交付物|配置|清单」逐行拼串做 FNV-1a 32 位(UTF-8 字节)。 */
export function fingerprint(hb: Handbook): string {
const norm = hb.chapters
.map((c) => `${c.ch}|${c.title}|${c.deliverable}|${c.config}|${c.check}`)
.join("\n");
const bytes = new TextEncoder().encode(norm);
let h = 0x811c9dc5;
for (const b of bytes) {
h ^= b;
h = Math.imul(h, 0x01000193) >>> 0;
}
return h.toString(16).padStart(8, "0");
}
/** 校验装配清单:章号 1..expected 齐全且唯一、三要素非空、登记的配置存在。 */
export function validateHandbook(hb: Handbook, availableConfigs: readonly string[], expected = 16): HandbookReport {
const chs = hb.chapters.map((c) => c.ch);
const missing: number[] = [];
for (let i = 1; i <= expected; i += 1) if (!chs.includes(i)) missing.push(i);
const dupChapters = chs.filter((c, i) => chs.indexOf(c) !== i);
const emptyFields: string[] = [];
for (const c of hb.chapters) {
if (!c.title.trim()) emptyFields.push(`${c.ch}:title`);
if (!c.deliverable.trim()) emptyFields.push(`${c.ch}:deliverable`);
if (!c.check.trim()) emptyFields.push(`${c.ch}:check`);
}
const known = new Set(availableConfigs);
const missingConfigs = hb.chapters
.map((c) => c.config)
.filter((f) => f !== "" && !known.has(f));
const valid = hb.chapters.length === expected && missing.length === 0
&& dupChapters.length === 0 && emptyFields.length === 0 && missingConfigs.length === 0;
return { chapterCount: hb.chapters.length, expected, missing, dupChapters, emptyFields,
missingConfigs, configCount: hb.chapters.filter((c) => c.config !== "").length,
fingerprint: fingerprint(hb), valid };
}
配套测试 core/test/o16_handbook.test.ts 把清单指纹写成金标准,并验「删一章」「登记不存在的配置」两种破坏都能被判无效:
// file: core/test/o16_handbook.test.ts
// tier: P
// verify: node --test 'core/test/o16_*.test.ts'
//
// 硬断言:手册装配清单校验通过,且清单指纹与 Python 侧 FNV-1a 实现逐位一致。
import { test } from "node:test";
import assert from "node:assert/strict";
import { readFileSync, readdirSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
import { validateHandbook, fingerprint } from "../src/o16/handbook.ts";
const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", "..");
const hb = JSON.parse(readFileSync(join(ROOT, "config", "o16_handbook.json"), "utf8"));
const available = readdirSync(join(ROOT, "config")).filter((f) => f.endsWith(".json"));
test("清单指纹与 Python FNV-1a 一致(跨语言对拍)", () => {
assert.equal(fingerprint(hb), "cd875fac");
});
test("装配清单校验通过:16 章齐全、章号唯一、三要素不缺、配置存在", () => {
const rep = validateHandbook(hb, available);
assert.equal(rep.chapterCount, 16);
assert.deepEqual(rep.missing, []);
assert.deepEqual(rep.dupChapters, []);
assert.deepEqual(rep.emptyFields, []);
assert.deepEqual(rep.missingConfigs, []);
assert.equal(rep.valid, true);
});
test("第 15 章为案例复盘,无独立配置,不计入配置数", () => {
const rep = validateHandbook(hb, available);
assert.equal(rep.configCount, 15);
assert.equal(hb.chapters.find((c: { ch: number }) => c.ch === 15).config, "");
});
test("缺一章即判无效:删掉第 9 章后 missing 命中", () => {
const broken = { ...hb, chapters: hb.chapters.filter((c: { ch: number }) => c.ch !== 9) };
const rep = validateHandbook(broken, available);
assert.deepEqual(rep.missing, [9]);
assert.equal(rep.valid, false);
});
test("登记了不存在的配置即判无效", () => {
const broken = { ...hb, chapters: hb.chapters.map((c: { ch: number; config: string }) =>
c.ch === 1 ? { ...c, config: "o99_ghost.json" } : c) };
const rep = validateHandbook(broken, available);
assert.deepEqual(rep.missingConfigs, ["o99_ghost.json"]);
assert.equal(rep.valid, false);
});
在本机跑 node --test 'core/test/o16_*.test.ts',11 个用例全过(含 16.2 的 6 条):
✔ 清单指纹与 Python FNV-1a 一致(跨语言对拍) (1.343333ms)
✔ 装配清单校验通过:16 章齐全、章号唯一、三要素不缺、配置存在 (0.714542ms)
✔ 第 15 章为案例复盘,无独立配置,不计入配置数 (0.202625ms)
✔ 缺一章即判无效:删掉第 9 章后 missing 命中 (0.206375ms)
✔ 登记了不存在的配置即判无效 (0.157292ms)
ℹ tests 11 ℹ pass 11 ℹ fail 0
fingerprint = cd875fac
fingerprint = cd875fac 是清单的指纹:同一份清单在 Node 的 handbook.ts 与 Python 的 FNV-1a 实现里算出同一个值(Python 侧一句 int 循环即可复算),说明「装配清单」这层也没有跨语言的口径分叉。这和第 12 章「一份 config、三种消费」是同一个信念:清单不是散文,是可以被程序读、被程序判的契约。
为什么清单是唯一真源
「写一本手册」和「写一份装配清单」的区别,在第一次更新时就会暴露。假设第 11 章的资质材料多了一项「网络文化经营许可证」,如果手册是一份 Word 文档,你得手工翻到第 11 章改正文、改目录、改检查表——三处漏一处就是一次事故。而清单是数据,正文与目录都从它渲染:
- 目录:按
ch排序直接生成,不会漏章; - 检查表:每章的
check就是一条可勾选项,不用另抄一遍; - 配置汇总:
config字段一列,谁的配置改了、有没有登记,一比对就知道。
更关键的是,清单可以被程序判对错。人手写的手册没法自动验证「16 章齐不齐」,但 validateHandbook 可以在每次提交前跑一遍:缺章、重复、空字段、幽灵配置——四类错误全部机械可查。这就是把「手册」从文档降格成数据的投影换来的好处。
一个容易忽略的细节是第 15 章:它是案例复盘,交付物是一份文档而不是配置,所以 config 字段留空。校验器对此的处理是「空配置合法、不存在的配置非法」——空是「本章没有配置文件」,写了一个 o99_ghost.json 才是「登记了不存在的东西」。两者的区别很重要:前者是设计,后者是 bug。
手册的边界:内容不可复现(X 层)
必须把边界划清。本节能机械保证的是结构:章号齐、字段全、配置存在、指纹稳定。下面这些属于 X 层,需真实业务环境,命令行不可复现:
- 每份交付物的实际内容(账户结构、素材矩阵、结算单、资质材料),要靠真实投放后台、真实平台条款与真实监管流程产出;
- 每章
check的实际通过与否,取决于真实运营结果,不是清单能判的; - 手册交付给谁、对方是否认可,是组织与商务问题,命令行不可复现。
工程上正确的切法与前几章一致:结构层可复现、内容层不可复现。结构层保证「手册没漏东西、没登记错东西」,内容层靠拿到真实材料后反填进清单(把实际交付物挂到对应章号上),结构校验立刻重跑一遍。这也是 16.3 交付物清单与本节装配清单共用同一套章号的原因。
16 章装订表
校验通过后,手册的目录就是清单的一个投影。下表是装配结果的速览(完整清单见落盘 config/o16_handbook.json):
| 章 | 交付物 | 配置来源 | 验收清单要点 |
|---|---|---|---|
| 1–3 | 账户/出价/素材配置表 | o01–o03 | 四级层级齐全、爬坡配止损、素材编号可追溯 |
| 4–6 | 归因窗口/聚合差异/广告位表 | o04–o06 | 归因窗口写明、接入差异对照、广告位 ID 唯一 |
| 7–8 | 内购流程/合规清单 | o07–o08 | 订单状态机闭合、广告红线可查 |
| 9–10 | 渠道分级/商务筹码表 | o09–o10 | 分成与账期逐渠道写明、筹码与底线量化 |
| 11–12 | 资质材料/结算周期表 | o11–o12 | 材料齐全倒排上线、扣点顺序与账期拆解正确 |
| 13–14 | 运营 SOP/单位账与月度账 | o13–o14 | 指标挂例会、CAC/ARPDAU/LTV 口径一致 |
| 15–16 | 复盘文档/手册与对账 | o16_handbook | 复盘可追溯、手册自洽、对账残差在容差内 |
自检表
| 检查项 | 合格标准 |
|---|---|
| 章号覆盖 | 1–16 齐全、无缺号、无重复 |
| 三要素 | 每章交付物/配置来源/验收清单非空 |
| 配置存在 | 登记的配置文件名在 config/ 下真实存在 |
| 指纹稳定 | 清单未改则指纹不变,交接可比对 |
| 边界清晰 | 交付物内容与验收结论标 X,不写成「实测」 |
手册装配解决了「东西在哪、算不算完成」,但清单自洽只说明结构没问题,不代表账算得对。下一节我们把各章的账拉到同一张台账上,用共享的经济模型复算一遍,看跨章的指标对不对得上。
阅读导航:上一节:15.3 关键决策对照表 · 下一节:16.2 全链路对账与仿真验收 。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。