ADR 0089 — analytics 和 delivery-metricas 成为报表脚本
- 状态: 已接受
- 日期: 2026-08-16
- 背景: 产品负责人决定提前实现目标模型(
docs/fluxo.yml)中的两个角色,而不等待自然触发 - 姊妹文档: ADR 0085
(
docs/fluxo.yml);形式上的直接先例:apps/api/scripts/medir-execucao.ts(第 13b 阶段)
背景
docs/fluxo.yml 早已把目标模型的两个角色描述为
status: proposto,每个都已写好变为 active 所缺的分离标准:
analytics(Analytics Engineer,产品指标)——“被medicao吸收(它只覆盖执行指标)”,标准为“metricas-de-produto成为 PO 必需输入的那一天”;delivery-metricas(Delivery Manager,流程——DORA)——“被medicao(部分)吸收”,标准为“永远不会成为 agent;成为medicao的报表(从 event log +gates.yml提取的 lead time、deployment frequency、MTTR、change failure rate)”。
两个触发都没有自然发生。产品负责人仍然决定提前构建:会话 → commit → PR → merge 的漏斗以及一片真实的 DORA(lead time、deployment frequency)已经可以从产品早已记录的数据中提取——dev agent 产生的三种 git 动作的 proposed_actions.execution_result
(apps/api/src/domain/git/git-action-execution-result.ts)以及 backmerge gate 的 docs/gates.yml。等待自然触发会推迟一个早已可行的报表。
决策
两个角色在 docs/fluxo.yml 中变为 status: active,实现它们的是一个脚本——apps/api/scripts/analise-funil.ts
(pnpm --filter api analise:funil -- --projeto <uuid> [--json])——与 apps/api/scripts/medir-execucao.ts 相同的格式:
NestFactory.createApplicationContext(AppModule)、必需参数 --projeto <uuid>、经由 Drizzle 的纯读取、对数据库零写入、默认输出 Markdown、--json 供程序化使用。
这不是一个新的产品功能:这是 docs/fluxo.yml 本身早已为这两个角色规定的形式,只是在预期触发之前构建。没有 GenServer,没有 LLM agent,没有新的 HTTP 路由。
脚本真正测量的
- 真实漏斗(
calcularFunil):有多少会话产生了至少一个executed的git_commit、一个pr_open和一个git_merge,以及相邻阶段之间的转化率。计数的是会话,不是动作。 - 真实 lead time(
calcularLeadTimes):从同一会话第一个executed的git_commit到第一个executed的git_merge,使用updated_at——即ExecuteGitActionUseCase真正写入execution_result的时刻,而不是动作被提出的时刻。 - 真实 deployment frequency(
deploymentFrequencyPorDia):targetBranch位于PROTECTED_BRANCHES中的executedgit_merge,按天分组。通过引用与backmergegate(docs/gates.yml)交叉——它的证据是 CI(.release/gate.json),超出只读数据库的脚本的范围,因此没有任何数据连接,只是同一个分支切分。
脚本声明缺失的,以及为什么这不是“缺少的数据”
三个指标位于输出的“Não medido, de propósito”一节中,只要以下前提不变,保持这种状态的决定就是永久的——不是下一轮要填补的缺口:
- 完整的产品漏斗(构思 → commit)。
sessions没有storyId——RN-230 已在 Criativo 标签页(apps/web/src/routes/ProjectSessionsTab.tsx)中声明了这一缺口。关闭它需要新 schema(新列,可能是sessions中的迁移或一张关联表),按原则不在本战线范围内:本轮没有迁移。 - 按功能的采用证据。 与第一项不同,这不是缺少收集的数据:这是产品今天没有任何路径可以拥有的能力。Brabo 不对它所构建的项目做埋点——没有从生成代码流出的使用遥测流水线,也没有关于它将如何存在的产品决定。在这里声明“缺失”遵循与 ADR 0042 对模型评分以及 ADR 0077(RN-210)对“理想”排名相同的原则:绝不以一个看起来真实的数字来近似。
- MTTR 和 change failure rate。 两者都需要真实生产事件的信号,这与
docs/fluxo.yml已为secops-runtime/platform角色(status: proposto/planned,启用与DEPLOY_ENABLED同步)记录的依赖相同。这是另一条战线的工作,不是本战线的。
后果
docs/fluxo.yml:analytics和delivery-metricas从status: proposto变为status: active,saidas_alvo被改写为saidas(今天真实的东西),外加一个显式的lacunas字段(仍为status: lacuna的东西,不删除声明)。apps/api/package.json:新条目"analise:funil"。- 没有迁移,没有新的 HTTP 路由,没有新界面。
docs/business-rules.md中的 RN-320..322 覆盖脚本的形式(RN-320)、漏斗和 lead time 的语义(RN-321),以及 deployment frequency 加上三项声明的缺失(RN-322)。
考虑过的备选方案
等待每个角色的自然触发。 这是 docs/fluxo.yml 的默认计划,并且对其他 proposto 角色仍是团队模型的默认行为。在这里被拒绝只是因为产品负责人明确决定提前——这不是在没有同等决定的情况下提前其他 proposto 角色的先例。
一个读取数据库并叙述漏斗的 LLM analytics agent。 被拒绝,依据的正是 docs/fluxo.yml 已为 delivery-metricas 声明(“永远不会成为 agent”)、本决定扩展到 analytics 的分离标准:报表是确定性的——求和、分组、按状态过滤——不需要模型来解读。这里的 agent 将是没有信息收益的 LLM 成本。
用代理指标近似这三个缺失的指标(例如把 chat.message 计为“使用”的代理,或把到下一个 commit 的时间当作 MTTR 的代理)。被拒绝:一个看起来像真实指标却不是它的代理,正是 ADR 0042 早已为模型评分点名的错误——带有书面原因的“—”胜过一个教错的数字。
参考
docs/fluxo.yml(块id: analytics、id: delivery-metricas)apps/api/scripts/analise-funil.ts/apps/api/scripts/medir-execucao.ts(形式先例,第 13b 阶段)apps/api/src/domain/git/git-action-execution-result.tsdocs/gates.yml(gatebackmerge)- RN-230——构思 → commit 的缺口,已在 Criativo 标签页中声明
- ADR 0042——绝不伪造不存在的数据的原则
- ADR 0077——同样的拒绝应用于“理想模型”