Files
patbond-doc/docs/development/iterations/iteration-4/00-kickoff-index.md
T
lixi 79b33dba31 docs: M4「AI 创作」开工分析八份报告 + 汇总拍板页入档挂导航
八角色并行开工分析,合计 7448 行;另出 00 汇总页(跨角色收敛结论、
13 项待拍板、6 项待仲裁分歧、未取证项汇总),挂第四迭代导航最前。
mkdocs build --strict 通过。

基线实测修正(文档与实况不符):
- api 测试 381(releases.md 记 379,成因待仲裁)
- 埋点白名单 41(四份文档记 42,experiment_exposed 重复计数)
- 真机验证挂起 10 项(转述链 4→6→8→10 每跳丢项)
- E2E 断言机械可数 226(声称 234 无可复核来源)
- v0.4.0 实际发布 09-14 11:17;CI 非红,三仓五上下文全绿

多方独立收敛(无需拍板):
- 队列用 Postgres SKIP LOCKED + 租约列,不引入 Redis/MQ
- 服务端零对象写能力(ObjectStorage 无 put/get),M4 立足点缺地基
- 「四模块字节级快照锁 CI」不存在,实际门禁仅结构断言
- 定稿模型 input_asset_id NOT NULL,即图生图不支持文生图
- 跨 schema 外键补回是 V5 自身指令,裁剪理由已不成立

阻塞项与安全缺口:
- AI provider BLOCKED:零 SDK/endpoint/额度,正典种子即 fixture
- 分支保护必需上下文选错触发器:(push) 限定 branches:[dev],
  致「推 dev 即满足门禁」且「非 dev 分支 PR 永久无法合并」
- check-secrets.sh 对 sk-/sk-ant- 零覆盖,须先于任何 AI key 落地
- 北极星 09-21 窗口已于 09-13 关闭,补救无从下手,建议改事件驱动

本批核心教训:13 处文档/注释与代码相反且多已被下游采信,其中
5 处造成实际规模误判(widthPx M→S、数据模型早已定稿 L→M、
社区侧 purpose 校验实际不存在等)。汇总页 §0 立转述纪律。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-14 15:48:56 +08:00

207 lines
24 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# M4「AI 创作」开工汇总
**日期**2026-09-14 **状态**:开工分析完成,待拍板 **上一迭代**M3.5 收官、v0.4.0 已发布
---
## 0. 本页的使用纪律
本页是 8 份开工报告(合计 7448 行)的**转述层**,存在的目的是让拍板不必翻全文。
但本批分析最大的发现恰恰是**「转述即污染」**:十余处文档与注释所写与代码实际所做相反,且多数已被下游报告采信,直接造成过规模误判(见 §6)。因此:
- 本页每条结论都标注**来源报告编号**(如 `[02]`)。要动手实现或据此拍板时,**回读该报告的取证行号,不要止步于本页**。
- 本页**不新增任何结论**。凡本页出现而来源报告中没有的判断,视为本页的错误。
- 各报告末尾均有「取证边界 / 未取证项」附录,汇总见 §7。**未取证项不得当事实使用**。
---
## 1. 报告索引
| # | 报告 | 行数 | 一句话 |
|---|---|---|---|
| 01 | [任务分解](01-pm-task-breakdown.md) | 742 | 28 工单 / 4 波 / 14 决策;推翻 8 处既有结论 |
| 02 | [后端技术评估](02-backend-technical-assessment.md) | 1114 | 队列方案、新模块、V6+V7、契约 +4/+5/+810 决策 |
| 03 | [Flutter 技术评估](03-flutter-technical-assessment.md) | 1670 | 自适应轮询、13 处 AI 模拟定位、测试 +30011 决策 |
| 04 | [现实核查](04-reality-check.md) | 687 | 总体 **NEEDS WORK**AI provider **BLOCKED** |
| 05 | [AI 创作 UI 规格](05-ai-create-ui-spec.md) | 1117 | 8 界面单元、等待态形态、新建 8 复用 16;18 决策 |
| 06 | [埋点与实验规划](06-experiment-tracking-plan.md) | 762 | 字典 41→49、eventVersion 定型、A/A 空跑;10 决策 |
| 07 | [基线证据审计](07-evidence-baseline-audit.md) | 550 | 基线逐条对账 6 对 3 错、真机项清点、发布流程一致性 |
| 08 | [Git 流程规划](08-git-workflow-plan.md) | 806 | 门禁漏洞、分支策略、契约升版顺序、v0.5.0 门禁;10 决策 |
决策总计约 **73 项**,本页只提炼需要跨角色协调或阻塞开工的部分(§3、§4);其余为各报告内的细节决策,随工单执行时就地拍板。
---
## 2. 基线实测(开工基准)
三仓工作区洁净、均停 `v0.4.0`HEADapi `dev@3cd8005` / flutter `dev@fbcd734` / doc `main@5cc6361``[07][04]`
| 项 | 文档声称 | 实测 | 裁决 |
|---|---|---|---|
| api 测试 | 379 | **381** | 文档错(成因待仲裁,见 §4-2)`[07][04]` |
| flutter 测试 | 597 | 597 通过 **+ 2 skipped** | 数字对,skip 从未披露 `[07]` |
| 埋点白名单 | 42 | **41** | 文档错,根因 `experiment_exposed` 重复计数 `[07][06]` |
| 真机验证挂起 | 8(或 4/6) | **10**M2 2 + M3 4 + M3.5 4 | 文档错,转述链每跳丢项 `[07][04]` |
| E2E 场景 | 42 | **42** | 对 `[07][04]` |
| E2E 断言 | 234 | 机械可数 **226** | 差异待仲裁,见 §4-6 `[04]` |
| 契约 v1.4.0 | 32/45/75 | 逐格相符 | 对 `[07][04]` |
| 四模块快照 | 字节一致 | md5 `a7081fb8…5801` 五处一致 | **副本一致为真,但无 CI 保证**(§6-2`[07][04]` |
| 契约矩阵 | 181 格 | 表格自洽,**不可机械复核** | 只存在于报告散文;代码唯一规模断言是 `operations()==45` `[04]` |
| Flyway | V1~V5 | V1~V5,无 V6`V5:48` `generation_job_id uuid,``REFERENCES` | 对 `[07][04]` |
| ADR | 001~022 | 22 条无缺号 | 对 `[07]` |
| 容器 | 六容器 | postgres/minio/auth/user/pet/community | 对;**无 Redis、无 MQ** `[07][02]` |
| 文档站 | 可构建无死链 | `mkdocs --strict` exit 0102 页零孤立 | 对 `[07]` |
| CI | 「仍红」(`iteration-3.5/04 §7.3` | 三仓五上下文 09-14 全 `success` | **过期快照,勿当风险继承** `[04][08]` |
| v0.4.0 发布时间 | 09-11 | **09-14 11:17** | 文档错 `[08]` |
---
## 3. 多方独立收敛的结论(证据已定,无需拍板)
| 结论 | 独立证实方 |
|---|---|
| **队列用 Postgres `FOR UPDATE SKIP LOCKED` + 租约列,不引入 Redis/MQ**。目标模型已备好六列租约字段与两条与出队/回收语句逐列对齐的部分索引(`patbond_postgresql.sql:605-716`,现成领取 SQL 在 `:1896-1917`);换中间件等于让这批列作废、推翻已评审模型。缺的只有租约超时回收器。 | `[01][02][04]` |
| **服务端零对象写能力**`ObjectStorage` 仅 4 方法,**零 `putObject`、零 `getObject`**。故「媒体链路可直接复用」只对读侧与客户端上传侧成立,Worker 落产物与喂输入均为净新增。**这是 M4 立足点缺失的一块地基。** | `[01][02][04]` |
| **「四模块字节级快照锁 CI」不存在**:CI 只有 `check-secrets.sh` + `mvnw test`,无任何 diff/校验和;实际门禁是结构断言(版本串 + 计数 + tag 操作集)。后果:只改 description 的契约漂移,四模块全都不会红。 | `[01][02][04][08]` |
| **定稿模型是图生图,不支持文生图**`input_asset_id uuid NOT NULL`。 | `[01][02][05]` |
| **「等真机设备」是伪阻塞**:本机 `Pixel_7` AVD 可启动、`/dev/kvm``crw-rw-rw-`、android-36 镜像在位,而 `device-verification.md:9` 明文接受「Android 真机(推荐)**或 Android 模拟器**」。 | `[04][06]` |
| **契约完全没有 429 / `Retry-After` / 任何响应头机制**`components.headers: []`,全契约 `headers:` 零命中);后端 429 亦零命中。M4 是首次引入。 | `[03][04][05]` |
| **跨 schema 外键的裁剪理由已不成立,补回是 V5 自己下的指令**`V5:15-19`/`V3:14-19` 原话为「FKs into schemas **not yet migrated** are STRIPPED」——理由是目标 schema 当时不存在;反证有 `V1:262-264``V5:45-46``V5:107` 三条在案的跨 schema 外键。 | `[02]` |
---
## 4. 必须开工前拍板
### 阻塞 V6 定稿与开工
| # | 决策 | 现状与推荐 |
|---|---|---|
| **A** | **AI provider 选型** | **BLOCKED**。零 provider SDK、零 endpoint、零额度;密钥面仅 4 项(DB/internal/MinIO×2);本机 AMD Vega 集显无 CUDA,自托管不可行。**最硬的反证:正典种子自己写的就是 `provider_code='fixture'`**,且 `generation_jobs` 三个快照列 `NOT NULL`,逼迫显式选边。推荐 **fixture provider 起步 + 可插拔适配层**(M4 四条验收标准全部与图好不好看无关,fixture 还能注入真实供应商难复现的故障)。**缺失的外部输入:生产服务器 GPU 情况、云 API 报价** —— 这是唯一真正卡住的外部依赖。`[01][02][04]` |
| **B** | **参考图必填(图生图)还是可选(文生图)** | 三方独立指出与工单描述「可选参考图」冲突;定稿模型 `input_asset_id NOT NULL`,正典原文亦为「上传一张照片…」。推荐**沿用 NOT NULL、图生图先行**。此项同时决定 V6 能否照抄目标模型、create 页整个交互、A2 的 gating 形态。`[01][02][05]` |
| **C** | **上游调用形态** | 推荐可插拔 `GenerationProvider` **两阶段 submit/poll**。两阶段是硬要求:否则「不重复扣费」的恢复路径永不被测试覆盖。stub 用 JDK 内置 ImageIO/Java2D 出真实字节,零新依赖。`[02]` |
| **D** | **新模块归属与命名** | 推荐新建模块、端口 `:8085`、前缀 `/api/v1/creation/**`。**命名存在冲突**`patbond-creation``[01]` vs `patbond-ai``[02]`。ADR-009 原文记载「后端评估建议 user 内包,**用户裁定新建模块**」。代价:`BearerAuthFilter` 将成第 4 份(community 版 Javadoc 自称 "Third copy")、存储/配置第 4 份、`UuidV7` 第 3 份。`[01][02]` |
| **E** | **4 件共享物是否上提 common** | 推荐同波次上提,退路是各抄一份。**本迭代最大回归面**,与 D 强耦合。`[02]` |
### 流程与安全(建议第一波,先于相关代码落地)
| # | 决策 | 现状与推荐 |
|---|---|---|
| **F** | **门禁必需上下文改为 `(pull_request)`** | 现状必需上下文为 `CI / backend-test (push)`,而 `ci.yml:16-17` 把 push 触发器限定在 `branches: [dev]`。**双重后果**:① 门禁实际由「推 dev」满足,**PR 侧检查红也能合并**;② **任何非 dev 分支 → main 的 PR 永久无法合并**head 永不产生 `(push)` 状态),使 `git-workflow.md:9` 的 hotfix 短命分支纪律实际是死的。正确上下文真名已从 CI 实跑记录取得(非猜测):`CI / backend-test (pull_request)` / `CI / flutter-gates (pull_request)`。**推荐替换而非追加**(追加不解除 hotfix 死锁),改完做一次**空 PR 验证**,勿拿正式发布当试验场。`[04][08]` |
| **G** | **`check-secrets.sh` 补 AI 凭证规则** | 现有 7 条规则对 `sk-`/`sk-ant-` **零覆盖**`KEY-ASSIGN` 只认 `access_key`/`secret_key` 不认 `api_key`,故 `ANTHROPIC_API_KEY=sk-ant-…` 全漏网。**必须先于任何 AI key 落地。** 另:三仓 `core.hooksPath` 全部 unset,防泄漏第一层完全未生效。`[08]` |
| **H** | **北极星 09-21 时限处置** | **窗口已于昨日关闭**,不是「来不及」:09-21 是 W37 队列(首记 09-07~09-13+8 天的成熟日,而 09-13 = 周日 = W37 最后一天,今日 09-14 已是 W38 第 1 天,此后产生的首记永远进不了 W37。**补救无从下手。** 且 W37 分母极可能为 0(真机执行记录全空、无分发、API 未对外、桌面 100% 丢弃)。推荐:档 A 把首次出数由**日期承诺改为事件驱动触发条件**(改写 `device-verification.md:40` 等两处)+ 档 B 09-21 仍出一次「基建就绪读数」(只报 SQL 可执行 + 实测分母 + 链路证据)。**明确否决**用桌面 override 或 curl 造数凑读数。另:北极星出数**至今无可执行 SQL 载体**,`iteration-2/06 §2.1` 的 SQL 只存在于报告正文。`[06]` |
| **I** | **发布流程固化去处** | 正典是一份标题至今写着「草案」的迭代报告,8 步里 4 步过期(第 2/3/4/6 步);`git-workflow.md` 全文 65 行无任何发布/PR/E2E 内容。推荐固化进 `git-workflow.md` 新章节,**E2E 份数只在一处写死**,其余位置表述为「全份」并链接过去(防复发)。`[07][08]` |
| **J** | **文档站访问控制** | 登记项仅为 `server-exposure.md` §2 表格里一个内联 `⚠️`,无责任人、无期限、「归属决策」列为空、未进 §5 行动记录。**102 页全部公开,含 `server-exposure.md` 自身、`ci-runner-setup.md`、以及 09-11 安全事件复盘**(端口清单、常驻服务、内部 API 路径、刚被攻击那台主机的注入路径与处置手法)。与 Gitea 同机同 nginx、共用 443、无鉴权层。**防护方式存在分歧**,见 §4-3。`[07][04]` |
| **K** | **进度反馈机制** | 推荐**自适应轮询**(1s×3 → 2s×5 → 3s,上限 5s,硬超时 5min),不做 SSE/WebSocket。决定性理由:现有网络层全部围绕「信封解包 + 401/40101 单飞刷新重放一次」构建(`api_client.dart:97-131,163-176`),SSE 两条都用不上,**等于旁路整条已建好的鉴权链、形成第二套鉴权路径——而 M3.5 端口事故的根因正是「跨模块调用绕开既有接线纪律」**;且两侧流式基础设施均为零(后端 `SseEmitter` 0 命中、客户端 `ResponseType` 0 命中);**A 是 B 的真子集**(任何推送方案都必须有「查状态」GET 兜底,有了它轮询已免费到手)。`[03][05]` |
| **L** | **中断恢复的事实来源** | 推荐服务端「我的进行中任务」端点,**不做本地持久化**。理由:与「服务端是唯一事实来源」纪律一致;全仓刻意没有任何业务任务态被持久化(M3 防泄漏成果),开这个口子须在 `app.dart:242-249` 再加一处清理,漏则是安全缺口;换设备场景下本地方案完全失效。`[03]` |
| **M** | **eventVersion 定型** | 定为「**每个事件自身的 props schema 版本**」,否决「字典世代」读法。决定性理由是**可修复性不对称**:此读法下客户端现行硬编码 `1` **本就正确**(零改动零回填);「字典世代」读法下全部历史行皆错且不可修复(`server_ts` 无法反推事件当初属于哪代字典)。落地:白名单 key 改 `(name, version)` 二元组 + 新增逐条拒绝原因 `unknown_event_version`——**必须放逐条路径,不可放 DTO 校验,否则重犯 platform 的整批连坐错误**(见 §6-1)。`[06]` |
---
## 5. 待仲裁:agent 之间的分歧(6 项)
| # | 分歧 | 两方主张 |
|---|---|---|
| 1 | **新模块命名** | `patbond-creation``[01]`vs `patbond-ai``[02]`)。端口 `:8085` 与前缀一致,仅名称不同。 |
| 2 | **api 测试 381 的成因** | `[04]``3cd8005` 就是那次「379→381」的契约冻结提交,`releases.md:17/:35``feature-checklist.md:5` 照抄了冻结前的数(给出 3+131+40+100+107 分解)。`[01]`379 是 surefire 报告数、381 是注解数,属参数化展开差异、非回归。**两解释互斥**;`[04]` 给了可核的分解,倾向 `[04]`,但两方均未联合复跑。 |
| 3 | **文档站防护方式** | `[07]`:IP 白名单(单读者、纪律 6 下不必新增凭证),或内容分层把三份敏感文件剔出公开构建。`[04]`basic auth。 |
| 4 | **A/B 前置状态口径** | `[01]`:**5 绿 3 半**(分流哈希、Flutter 曝光封装、feature flag 三者代码零实现)。`[06]`:**放行条件 0/6 满足**,故 M4 首个「实验」应为 **A/A 基建验证空跑**(零产品风险,≥200 曝光即可暴露分流失衡与曝光漏报)。两者可能在数不同的东西(前置组件 vs 放行条件),需统一口径后再排期。**注意:原文档「6 绿 1 半」两方均否定** —— 按它排期会在实验启动日才发现要先写三个组件。 |
| 5 | **429 错误码个数** | `[02]`:单码 `42900``[05]`:**必须拆两个码** —— 配额耗尽等的是明天(弹 sheet 给出口),频率过快等的是几秒(弹 SnackBar),共用一码必然有一半场景的文案和出口是错的。 |
| 6 | **E2E 断言数 226 vs 234** | `[04]`:机械可数 226210 `check(` + M1 16 `✗`)。`[07]`:静态调用点 207,缺口**可能**由循环执行产生但原报告从未说明。声称值 234 无来源可复核。 |
**两处属细化而非冲突,一并记录**
- **SegmentedButton 债的优先级**`[01]` 改判搭车 M4(create 页分段器正是改造对象,一次修 6 处,边际 S);`[05]` 实测 `secondaryContainer #FFDAD2` + `onSecondaryContainer #5D4038` **对比度 7.19:1 达标**,故是 **P2 品牌一致性债、非 P1 无障碍债**,不应为它拖 M4 范围。`[03]` 补根因:主题层无 `segmentedButtonTheme` 亦无 `chipTheme`0 命中),与 M3.5-01 修 DatePicker **完全同构**`app_theme.dart:215-296` 是现成样板。→ 结论:搭车但降级为 P2。
- **`widthPx/heightPx` 的归因**`[01][04]` 记为服务端缺尺寸探测;`[03]` 拆成**三段事实** —— 详情页客户端**已正确消费**(`post_detail_page.dart:515-521` 有 clamp,服务端一给即生效)、Feed 卡片是**客户端硬编码缺陷**(`post_card.dart``post_media_grid.dart:326-327` 硬编码 4:3,维度可用却被忽略)、**客户端根本无法提供维度**(`CreateMediaUploadRequest` 契约无该字段)。→ 必须两侧同批改,只修一侧用户零感知。`[05]` 补严重度判断:不是「更严重了」而是**「从看不见变成看得见」**——A4 用 job 自己的 width/height 画出完整构图、发到 Feed 后被裁成 4:3,是**同一次会话内的直接前后对照**,9:16 竖图裁掉约 58%,用户结论会是「发布把我的图裁坏了」。修复成本极低(Worker 写 output asset 时 job 的 width/height 就在手里)。
---
## 6. 「文档与代码相反」清单(本批核心教训)
M3.5 曾因一句转述(报告写「无 nickname 字段」实指「契约未暴露」)把规模预估**高估一整档**。本批发现该模式**远非孤例**:
| # | 说谎处 | 实际情况 | 已污染范围 |
|---|---|---|---|
| 1 | `analytics_service.dart:99-102` 注释称「逐条 rejected、不影响客户端」 | **与实现相反**`TrackEventsRequest.java:16``@Valid` 级联到列表元素 → 任一元素失败即整请求 400 → 客户端 `:273-281` 视为永久拒绝并**整批删段**。**这是一个与平台无关的「毒丸批次放大器」**:任何一条事件的任何一个字段失败都会毒死整批 50 条。桌面采集能力为零。 | 转述进 **5 处文档** `[03][06]` |
| 2 | CI 自称 "byte-identical"、文档称「四模块字节级快照锁 CI」 | CI 零 diff、零校验和;md5 比对是人工步骤 | 4 份报告 `[01][02][04][08]` |
| 3 | `releases.md` 同一文件 `:36/:56`「四份」vs `:131`「双份」 | 前瞻侧(给 M4 用的那条)写错,照它执行漏跑 **17** 个场景 | `[07][04][08]` |
| 4 | 发布 checklist `iteration-3/08:84`「跑 M2+M3 **两份**」 | 应为全份;且该 checklist 标题至今是「草案(验证后固化进 `git-workflow.md`)」,**固化从未发生**grep `git-workflow.md``checklist\|发布\|E2E\|PR` 零命中) | `[07][08]` |
| 5 | `openapi.yaml:1228`「purpose 仅 `post_image`」 | 与 `:3460` 三值枚举矛盾(M3.5 加值时漏改端点描述)。M4 再加值必须一并修,否则第三次漂移 | `[03]` |
| 6 | `PostMediaAttachIntegrationTest:44-45` 断言 640/480 **是绿的** | 靠 `CommunityTestData:55` 夹具直插。**测试绿 ≠ 生产有值**,生产恒 null | `[04]` |
| 7 | `feature-checklist.md:218`「community 域 19 条」 | 算术错误,代码自身注释拆分为 8+2+8=**18**`experiment_exposed` 被重复计数;`EventDictionaryTest` **零条数断言**故漂移不可见 | 4 份文档 `[07][06]` |
| 8 | `releases.md:17/:35``feature-checklist.md:5` 的 379 | 照抄了契约冻结前的数,实测 381 | `[04][07]` |
| 9 | `releases.md:121` 整段漏掉 M3.5 | 真机项转述链 **4→6→8→10 每跳都在丢项** | `[04][07]` |
| 10 | `releases.md:47`「分支保护确实要求该 (pull_request) 检查」 | 表象对、机制归因错:真正解锁合并的是 09:44:05 转绿的 `(push)` | `[08]` |
| 11 | `iteration-3.5/04 §7.3`「CI 仍红」 | 过期快照;同一 run 73 已于 09-14 09:38 重跑、09:44 转绿 | `[04][08]` |
| 12 | `iteration-3.5/05``integration_test/` 证「桌面链路可用」 | 那 4 份真机测试**完全在 `flutter test` 之外**,无任何门禁会跑。凡「桌面/真机实测已验证」一律降级为「有脚本,无门禁」 | `[07][03]` |
| 13 | M3 建议「话题随 `ai_creation` 一起做」 | `ai_creation` 只是 category 枚举值,与 topics 表**零字段关联**,搭车理由不成立 | `[01]` |
**由此造成的既有误判(本批已纠正)**
- `widthPx/heightPx` 规模 **M→S**(列早已存在于 `V1:217-218`,缺的只是尺寸探测)`[01]`
- 「M4 需设计数据模型」→ **完整设计早已定稿**(3 表 40 列 11 索引),且**零跨 schema FK 需裁剪**T4-01 由 **L→M** `[01]`
- 「社区侧有 purpose 白名单校验」→ **不存在**`PostService.validateAssets:343-358` 只校验归属 + ready`MediaAssetRef.java:9-16``MediaAssetGateway` 的 SQL 均不含 `purpose` 列(对比 pet 侧 `PetService.java:196` 确有校验)。**后果:不补强制校验,「AI 创作」标签可被任意图片伪造。** `[02]`
- 「需评估 DB / Redis / MQ 三选一」→ 前提本身多余,目标模型已把租约队列设计完(§3)`[02][04]`
- 「A/B 前置 6 绿 1 半」→ 两方均否定(§5-4)`[01][06]`
---
## 7. 未取证项汇总(不得当事实使用)
| 项 | 缺什么 | 阻塞谁 |
|---|---|---|
| 生产服务器 GPU 情况、云 API 报价 | 外部输入 | **决策 A(阻塞开工)** `[01]` |
| E2E 断言精确值(226 / 234) | 脚本无计数器;循环执行未证 | 门禁数字口径 `[04][07]` |
| 契约矩阵 181 格 | 只存在于报告散文,无机械可数载体 | 契约漂移检测可信度 `[04]` |
| 分支保护「禁直推」的具体机制 | `/branch_protections` 返 401`/branches/main` 匿名可读故主结论仍成立) | 决策 F 的复核 `[08]` |
| E2E 零失败重跑、零迁移实证 | compose 未起 | 发布门禁复现 `[04][07]` |
| `check-secrets.sh` 实际效力 | 未实跑 | 决策 G `[04][07]` |
| 服务器侧实际暴露面 | 只做了文档取证,未探测服务器 | 决策 J `[04][07]` |
| 服务端是否探测图片尺寸、`page_viewed` props 取值集合 等 6 项 | 见 `[03]` 附录 A | 相关工单 `[03]` |
| 实验设计模板文档实体、北极星出数 SQL 载体 | 均无实体 | 决策 H `[01][06]` |
| 厂商侧参数配比、配额默认值、单机资源余量 | 需产品/运维确认 | 后端工单 `[02]` |
---
## 8. 规模概览(各报告独立估算,未经交叉校准)
| 维度 | M4 预期 | 来源 |
|---|---|---|
| 工单 | 28(含 3 条件单),S×5 / M×16 / L×44 波 | `[01]` |
| 关键路径 | 4 个 L 单:后端队列 2 + 客户端状态机 2(与 M3「媒体双端占其二」同型) | `[01]` |
| Flyway | **2 个**V6creation schema 三表 + 13 索引 + 3 触发器 + 补回 `posts.generation_job_id` 外键)、V7(目录种子)。creation schema 零结构偏离,逐列抄目标模型 | `[02]` |
| 契约 | v1.4.0 → **v1.5.0 纯增量**+4 路径 / +5 操作 / +8 schema32/45/75 → **36/50/83**)、+3 错误码、改 4 个既有 schema;零删除零重命名零必填收紧。「一键建草稿」复用既有 `POST /api/v1/posts`**0 新增路径** | `[02]` |
| 客户端页面 | 6 页(4 AI + 2 搭车:我的收藏 / 我的草稿) | `[03]` |
| UI 界面单元 | 86 页 + 1 sheet + 1 全局层),新建组件 8 / 复用 16(6 需小改) | `[05]` |
| 客户端测试 | 597 → **约 897**(建议 +300 | `[03]` |
| E2E | 42 → **54 场景**;新增第五份 `test_e2e_m4_manual.dart` | `[03][08]` |
| 埋点字典 | **41 → 49**(新增 8 条 `creation` 域 + 2 处既有事件加属性 + 启用 `experiment_exposed`,废弃 0 | `[06]` |
| demo 消亡 | `create_page.dart` **563 行 → 约 40 行**13 处模拟) | `[03]` |
---
## 9. 今天即可执行的两件事
1. **M2 两项真机验证** —— 约 **55 分钟**(其中 35 分钟纯等待),模拟器合规、`Pixel_7` AVD 已就位,只差导出 `ANDROID_HOME`/`PATH`。**已白拖 6 天**;虽已错过 W37 窗口(决策 H),但它把最早可得读数从「无限期」拉到 **2026-09-28**`[04][06]`
2. **`check-secrets.sh` 补 AI 凭证规则** —— 决策 G,须先于任何 AI key 落地。`[08]`
---
## 10. 必须与写侧同批修掉的两处(否则 M4 制造新缺陷)
1. **数据损坏路径**`post_compose_page.dart:209-211` 把恢复的 AI 草稿类目静默降级为 `general`。现在无害(写侧被封),**M4 放开写侧后会把类目改错并写回服务端** —— 必须与放开写侧同一个提交改掉。`[03]`
2. **`CommunityMigrationIntegrationTest.java:81-88` 断言 `fkCount == 0`** —— V6 补外键**必然让它变红**,需拆成 generation=1 / region=0。提前知道可省一轮排查。`[02]`
---
## 11. 两条会影响 M4 观感的客户端纪律
1. **绝不能承诺推送**:客户端**无任何推送能力**(无 WS/SSE/FCM/相关端点)。等待页写「完成后通知你」会让用户锁屏等推送然后什么都收不到。正确说法是「回到 App 就能看到结果」。`[05]`
2. **不要押注百分比进度**`generation_jobs` 的 CHECK 规定 `queued` 时 progress 恒 0、`running` 时 progress 无下限约束,押注「会有百分比」的后果是**最常见观感变成「0% 卡住」**。故主形态为阶段文字 + 不确定进度环,`progress>0` 才叠确定型数字;**不展示 ETA,改展示已用时**(已用时是事实,ETA 是承诺,而 M4 给不出可信 ETA)。另需定义服务端 5 个 status 之外的**第六个 UI 态:僵死/超时**(`running` 超阈值),且它不是错误态。`[05]`
---
## 12. M4 核心指标当前算不出来
两个 post 事件(`post_publish_succeeded``post_draft_saved`)的现行白名单**无任何标识帖子来源的属性**,因此「AI 生成 → 发帖」这条 **M4 最核心的转化在现行字典下根本不可计算**。处置:各加 `creationTaskId`。另建议补一条**断言白名单条数**的测试——本批 41/42 漂移之所以四份文档不可见,正因 `EventDictionaryTest` 零条数断言。`[06]`