承接目录治理:上轮只压缩内容未减文件数,闭线工作记录仍平铺致目录看着仍一堆(创始人指出)。本次执行 B2 归档。 64 个 ≤06-15 闭线档(25 压缩桩 + 闭线 review/report/纪要/edit-plan)git mv 入 docs/agent-specs/_archive/(文件名不变、仍 git 跟踪可查)。热目录 ≤06-15 仅留 13 活档(决策/纲领/SoT/活spike)+13 个 06-16 在飞。 活资产 20 处旧路径引用(.agents/docs/memory/_index)同步改 _archive/,引用断裂复测=0;_index 活地图 + 治理档状态收口。约束:0 个 06-16 被移、orchestrator 等未跟踪在飞档零误纳。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
161 lines
15 KiB
Markdown
161 lines
15 KiB
Markdown
<!-- /autoplan restore point: /root/.gstack/projects/zizi-al-games-development-ai/dev-2.0.0-autoplan-design-restore-20260609-084100.md -->
|
||
<!-- v2 收缩重构版:经 /autoplan CEO 双声音(Claude 子代理+Codex)评审 + 用户前提门 D1 确认。原 v1(经营全垂直)见 git history -->
|
||
# 设计 v2:最小数据闭环(clicker-plus 通用 runtime)+ 小卖部皮肤
|
||
|
||
> 文档号:HJ-DESIGN-006 | 日期:2026-06-09 | 分支:dev/2.0.0
|
||
> 上游:`docs/agent-specs/_archive/2026-06-09-下一阶段路线-plan.md`(autoplan 三轨定稿)的 **B 轨黄金闭环**。
|
||
> 评审:/autoplan CEO 双声音收敛"收缩重构",用户前提门 D1 确认。进度底账 `docs/mvp/MVP进度总账.md`。
|
||
> 下一步:转 writing-plans。
|
||
|
||
---
|
||
|
||
## 1. 背景与动机
|
||
|
||
B 轨 = 把 1 条完整垂直闭环做真,核心是**最小数据回路(遥测→quality_score→feed 排序)**。
|
||
|
||
**v1→v2 反转(autoplan CEO 双声音一致)**:v1 为「经营」模板专门扩 Runtime,被两个独立模型判为"把可演示游戏误当平台闭环"。v2 改为:**通用 clicker-plus 数据驱动 runtime + 确定性 PackageFactory**,经营/小卖部只是**配置皮肤 + 内容样例**,不主导架构。这样同样产出"小卖部"体验,又沉淀可复用的平台生产能力,避免每品类加 Runtime 分支。
|
||
|
||
**可行性勘察实证(只读代码)**:前端 Runtime 已动态读 `gameConfig.target`/`assets`,但玩法逻辑硬编码、`manifest.entry` 从不执行;后端 aigc/runtime/telemetry 全桩,feed-api 无 `FeedApi`、publish 不写 feed、`game_runtime_package` 无列存整包 JSON。
|
||
|
||
---
|
||
|
||
## 2. 目标 / 非目标
|
||
|
||
**目标:证明平台「生产→分发→采数→排序」的复用能力**(非"做一个游戏"):
|
||
- 通用 clicker-plus 数据驱动 runtime + PackageFactory:同一套数据化配置(点击/目标/时长/可选库存商品)产出不同皮肤的游戏。
|
||
- 最小数据回路真实跑通:play 事件真落库、quality_score 真算、feed 排序真读它(A/B 可证),**clicker-plus 即可验,不依赖经营皮肤**。
|
||
- 小卖部皮肤 + ≥10 个参数化种子内容,让 feed 不是"两个游戏赛马"。
|
||
|
||
**非目标(YAGNI):** 不为单品类扩 runtime(经营=配置皮肤);不做完整经营状态机;不接真实 LLM/Dify、MQ、OSS、runtime 真实编译;不做真实鉴权/多租户。
|
||
|
||
**口径收敛(对外措辞,CEO 双声音)**:本闭环达成 = "**数据飞轮埋点骨架 + 推荐反馈链路已跑通**",**不是**"护城河已建"(护城河要等真实创作者/玩家/反作弊/留存)。
|
||
|
||
---
|
||
|
||
## 3. 架构总览
|
||
|
||
```
|
||
[创作] studio.createDraft → project.createProject ✅已有
|
||
↓ 选 clicker-plus 模板 + 参数(点击/目标/时长/可选商品·皮肤)
|
||
[生成] aigc.generate → PackageFactory 确定性填充 → 合法 GamePackage(无LLM) 🔨桩→真
|
||
↓
|
||
[落包] runtime.persistPackage → game_runtime_package(READY) via PackageStore 🔨新建(V10加列)
|
||
↓ manifestUrl=后端端点(PackageStore.read)
|
||
[发布] project.submitPublish 门禁 → 状态机 ✅门禁已真
|
||
[可见] 进入"可见态"(批次1定义:终态可见 + package READY 双条件) ──钩子──→ 写 feed rank 🔨FeedApi.upsertRank
|
||
↓
|
||
[feed可见] feed.stream 读 rank + **回填本体(标题/封面/作者/packageUrl)** 🔨读端在,本体回填待补
|
||
↓
|
||
[试玩] 前端 getRuntimePackage→manifestUrl→通用 clicker-plus runtime 🔨数据驱动小扩
|
||
↓
|
||
[遥测] game_play_start/end(duration_ms,completed)/like/share + eventId 🔨桩→真(同步落库,经聚合服务接口)
|
||
→ /events/batch 同步写 event → upsert game_telemetry_game_stat(按天)
|
||
→ quality_score → **当日 stat 覆盖** game_feed_rank.quality_score/sort_score
|
||
↓
|
||
[排序] feed.stream 重查 → 排序反映新 quality_score ✅读端在
|
||
```
|
||
|
||
**3 个关键决策(已修正):**
|
||
1. **feed 写入挂"可见态"**:v1 误写 `APPROVE→PUBLISHED`,实际审核通过到 `APPROVED`、PUBLISHED 是另一状态(Codex critical)。→ 批次1 先读 `ProjectStatusEnum` + 状态机**定义 feed-eligible 态**(终态可见 AND runtime package=READY 双条件),feed 写入钩子挂这里,不把不可玩游戏推进 feed。
|
||
2. **manifest=后端端点 + `PackageStore` 抽象**:DB 是 MVP 实现,**V10 迁移加 `game_runtime_package.package_json LONGTEXT`(确定项,非开放项)**。退场契约:manifest-from-DB 是脚手架,M3 接 OSS/真实编译时整体下线,**不在其上叠功能**。
|
||
3. **quality_score**:`clamp(60×完玩率 + 20×like率 + 20×share率, 0, 100)`(完玩率=completed/play_start;like/share 率截断 1.0);**回灌口径=取该 game 当日 stat 覆盖 `feed_rank.quality_score`(跨天加权留 M5)**(修 stat 按天 / rank 按游戏 的语义裂,Codex critical);`sort_score=quality_score+boost`。
|
||
|
||
---
|
||
|
||
## 3.5 三段批次(数据回路 AC 与经营皮肤解耦,CEO 双声音)
|
||
|
||
| 批次 | 内容 | 验收 |
|
||
|---|---|---|
|
||
| **① 契约/状态机校正** | 定义 feed-eligible 发布态 / V10 manifest 存储 / `FeedApi` 契约(含本体回填字段)/ telemetry 幂等键(eventId) / defaultZone / IP 原创名 | 契约入库、V10 迁移就绪 |
|
||
| **② 最小数据闭环(clicker-plus)** | PackageFactory 产 clicker-plus 包→落包→发布后入 feed→试玩→事件落库→quality_score 回灌→**A/B 排序**。**不依赖经营皮肤/runtime 扩展** | **数据回路 A/B AC 在此锁定** |
|
||
| **③ 经营皮肤 + 种子** | clicker-plus 配置出"小卖部"皮(点击售卖+极简库存)+ ≥10 参数化种子内容 | feed 有内容池;**经营皮肤可降级**(撞 <15KB 先退纯 clicker,数据回路 AC 不动) |
|
||
|
||
---
|
||
|
||
## 4. 组件设计(职责 / 接口 / 依赖)
|
||
|
||
| # | 单元 | 职责 | 接口 | 依赖 |
|
||
|---|---|---|---|---|
|
||
| 1 | **clicker-plus GameConfig schema**(契约) | 约束通用 clicker-plus 配置(点击/目标/时长/可选商品列表/皮肤元信息) | `contracts/templates/clicker-plus.schema.json`;经营=该 schema 的一组参数+皮肤 | game-package.schema.json |
|
||
| 2 | **PackageFactory**(aigc 桩→真) | 给 templateId+参数 → 确定性产合法 GamePackage,无 LLM;多参数批量产种子 | `getTemplateList()` 返真模板;`generate` DONE 产物=骨架代入参数→校验 clicker-plus+package schema | #1、project |
|
||
| 3 | **PackageStore + runtime 落包**(新建) | 抽象包存储(DB=MVP impl);跳过真编译落 `game_runtime_package(READY)` | `PackageStore.persist/read`;**V10 加 `package_json LONGTEXT`**;`GET /app-api/runtime/manifest/{versionId}` | game_runtime_package(+V10) |
|
||
| 4 | **FeedApi.upsertRank + 本体回填**(新建·填结构缺口) | feed-api 加 `FeedApi`;upsert rank;feed.stream **回填标题/封面/作者/packageUrl**(否则空卡,Codex high) | `upsertRank(gameId,versionId,zoneId,qualityScore,boost)`;stream join project 本体 | game_feed_rank、project |
|
||
| 5 | **project 可见态钩子**(改) | 进入 feed-eligible 态(批次1定义)后调 `FeedApi.upsertRank` 写基线分;**不动门禁/状态机(D2锚点)** | 钩子挂"可见态 + package READY"双条件后 | #4 |
|
||
| 6 | **telemetry 同步落库+算分**(桩→真) | `/events/batch` 同步:写 event→upsert stat→算 quality_score→调 #4。**经聚合服务接口**(未来换 MQ 不改业务语义) | 替换 `dispatchToMq`;**幂等键含 `eventId/clientEventId`**(防 ts 变化重复刷分) | event/stat 表、#4 |
|
||
| 7 | **通用 clicker-plus runtime**(前端中度扩展) | 数据驱动读 gameConfig:点击/目标/时长/可选库存商品;皮肤化渲染。**先量当前 build 字节余量**(防撞 <15KB) | 扩 `startRuntime`;上报 `game_play_start`/`game_play_end`(duration_ms,completed)/`like`/`share`+有效 traceId+eventId | gameConfig(#1)、SDK |
|
||
| 8 | **6 开工前置项 + beacon/tenant**(前端) | VITE_API_BASE / mock 门控 / token=test1+tenant-id / **sendBeacon 走 baseURL**(否则绕过) / 种子 tenant_id=1 / vite dev | — | — |
|
||
|
||
**upsertRank 列级语义(消歧,Codex high)**:project 钩子写 `quality_score=COALESCE(existing, baseline)`(不下调);telemetry 写 `quality_score=新值, sort_score=新值+boost`(**必须能覆盖**)。因"可见先于试玩"正常无竞争,此为安全网。
|
||
|
||
---
|
||
|
||
## 5. 数据流 + A/B 验收
|
||
|
||
**主链路**:创作→PackageFactory 产 clicker-plus 包→PackageStore 落包(READY)→submitPublish 门禁→进可见态→钩子写 feed rank→feed.stream(回填本体)可见→前端 clicker-plus runtime 试玩→上报事件(eventId+traceId)→同步写 event→upsert 当日 stat→算 quality_score→当日覆盖 feed_rank→重查 feed 排序变化。
|
||
|
||
**A/B 验收(数据回路 AC,批次②,clicker-plus 即可,Codex critical 协议)**:备同 zone 同 boost 的 A/B 两个已"可见"clicker-plus 游戏 → 记初始 feed 顺序 → 只向 B 上报有效 `game_play_start+game_play_end(completed=true)+like+share`(带 eventId)→ 断言 `game_telemetry_event` 有原始行、当日 `stat.quality_score` 变大、`feed_rank.sort_score` 变大 → 重查 feed **B 排到 A 前** → **同 eventId 重发不重复计数** → 关 mock 仍通过 → **feed 卡片本体非空**(标题/封面真回填)。
|
||
|
||
---
|
||
|
||
## 6. 错误处理
|
||
|
||
| 失败点 | 处理 |
|
||
|---|---|
|
||
| PackageFactory 产物 schema 不合法 | task FAILED,不落包,studio 链态 FAILED,前端提示 |
|
||
| 包不存在(NOT_READY) | 前端走 demo 兜底——但黄金闭环要真包,落包失败=闭环断,**登记缺口**(不靠兜底掩盖) |
|
||
| **未到可见态/package 未 READY** | **不写 feed**(双条件);防不可玩游戏进流 |
|
||
| feed 卡片本体回填失败 | 缺本体的 rank 行不展示或降级占位;**不允许空卡冒充可见** |
|
||
| feed rank 并发(可见钩子 vs telemetry) | 列级语义分离(§4):钩子不下调、telemetry 权威覆盖 |
|
||
| telemetry eventId 缺失/重复 | 缺 eventId 拒;同 eventId 幂等去重(防 ts 变化重复刷分) |
|
||
| traceId 空 | 后端拒(已有);前端必生成 |
|
||
| mock token 401/加密/跨域 | autoplan 已覆盖 |
|
||
|
||
---
|
||
|
||
## 7. 测试与验收
|
||
|
||
- **批次② A/B 验收**(§5)=数据回路 AC,clicker-plus 即可,与经营皮肤解耦。
|
||
- **单元测试**:① PackageFactory(合法/非法参数验产物 schema + 批量产种子)② PackageStore(存/读整包 JSON)③ FeedApi.upsertRank(给分验 sort_score+幂等+本体回填)④ telemetry(灌 play_start/end 验 stat 累加+quality_score 公式+eventId 幂等+调 feed)⑤ project 可见态钩子(到可见态→调 FeedApi;未到→不调)⑥ clicker-plus runtime(给 config 验点击/目标/时长/库存)。
|
||
- **主 agent 独立复跑**(铁律)。
|
||
- **完成判据**:批次② A/B 全绿 + 单元绿 + feed 本体非空 + 浏览器肉眼演示。
|
||
|
||
---
|
||
|
||
## 8. 边界 / 回滚 / 风险
|
||
|
||
- **改动边界**:不动 project 门禁/状态机(D2锚点)、不动 feed 读端排序逻辑、不接 MQ/OSS/真编译/真 LLM;**telemetry 走聚合服务接口、包走 PackageStore**(换 MQ/OSS 不改业务语义)。
|
||
- **回滚单元(按 3 批次,各自 commit)**:①契约+V10 ②PackageFactory/PackageStore/FeedApi/可见钩子/telemetry 同步 ③clicker-plus runtime+经营皮肤+种子。后端非零改动,回滚=按单元 revert + cleanup SQL。
|
||
- **数据污染清理**:固定 traceId/eventId 前缀 + 固定 gameId 清单 + cleanup SQL + 表快照。
|
||
- **风险**:① clicker-plus runtime 撞 <15KB(缓解:先量字节余量;经营皮肤可降级退纯 clicker,数据回路 AC 不动)② manifest-from-DB 沉淀成债(缓解:PackageStore 抽象+退场契约)③ quality_score 低样本易刷(缓解:MVP 接受,置信度/去重/反作弊留 M5,对外口径不夸大)。
|
||
|
||
---
|
||
|
||
## 9. 开放项 / 依赖(批次①解决)
|
||
|
||
- **发布态定义**:读 `ProjectStatusEnum` + 状态机,确定 feed-eligible 态(APPROVED 即可见?还是 APPROVED 后再 publish 到 PUBLISHED?)+ package READY 双条件。
|
||
- **V10 迁移**(确定项):`game_runtime_package.package_json LONGTEXT`(注明大小上限与超限处理)。
|
||
- **defaultZone**:feed 默认专区 zoneId(读 project game_zone 或约定常量)。
|
||
- **IP**:种子内容用**原创换皮**(如"蓝莓妹的小卖部"/自造),不用真实"王蓝莓"IP(撞自家 ip/compliance 风门,对外材料有侵权尾险);"王蓝莓"仅内部代号。
|
||
- **种子供给**:≥10 参数化种子(PackageFactory 批量产),feed 内容池;与上游 plan §2.D 对齐。
|
||
|
||
---
|
||
|
||
<!-- AUTONOMOUS DECISION LOG -->
|
||
## Decision Audit Trail(autoplan · design review)
|
||
|
||
| # | 阶段 | 决策 | 分类 | 原则 | 理由 | 否决项 |
|
||
|---|---|---|---|---|---|---|
|
||
| 1 | CEO | 运行 Claude 独立 CEO 子代理 + Codex CEO 声音 | Mechanical | P6 | 双声音对抗评审(codex 已就绪) | 仅 subagent |
|
||
| 2 | CEO | **设计形态:收缩重构** | **USER-GATED(前提门 D1)** | P1+P5 | 两模型一致;用户确认通用 clicker-plus+皮肤 | 保留经营-specific runtime |
|
||
| 3 | CEO | 通用 clicker-plus 数据驱动 runtime + PackageFactory(经营=皮肤) | Taste→采纳 | P5 | 避免每品类扩 runtime 分支爆炸,沉淀复用能力 | 为 business 单独扩 runtime |
|
||
| 4 | CEO | feed 写入挂"可见态+package READY"双条件 | Mechanical | P5 | 修 APPROVE≠PUBLISHED 状态机错(Codex critical) | 挂 REVIEWING/错态 |
|
||
| 5 | CEO | V10 加 package_json LONGTEXT(确定项) | Mechanical | P5 | 现表无列存整包 JSON,包存 DB 必需(Claude/Codex critical) | 标"实现时确认" |
|
||
| 6 | CEO | quality_score 回灌=当日 stat 覆盖 rank | Mechanical | P5 | 修 stat 按天/rank 按游戏语义裂(Claude/Codex) | 一次性 upsert 不定口径 |
|
||
| 7 | CEO | telemetry 幂等键含 eventId/clientEventId | Mechanical | P1 | 防 ts 变化重复刷分(Codex high) | 仅 traceId |
|
||
| 8 | CEO | feed.stream 回填本体(标题/封面/作者/packageUrl) | Mechanical | P1 | 防空卡 demo 露馅(Codex high) | 只读 rank |
|
||
| 9 | CEO | 抽 PackageStore + telemetry 聚合服务接口 + 退场契约 | Taste→采纳 | P5 | 换 MQ/OSS 不改业务语义;防 DB-JSON 永久债 | DB/同步写死长期架构 |
|
||
| 10 | CEO | IP 原创换皮(非真王蓝莓) | Mechanical | P4 | 撞自家 ip 风门+对外侵权尾险 | 真实王蓝莓做招牌 |
|
||
| 11 | CEO | 拆 3 段批次(数据回路 AC 与经营皮肤解耦) | Taste→采纳 | P3 | clicker-plus 即可验 A/B;经营皮肤可降级 | 单批次绑死 |
|
||
| 12 | CEO | 对外口径=埋点骨架/反馈链路(非护城河) | Mechanical | P5 | 2 游戏少量遥测不证护城河 | 夸大为护城河已建 |
|
||
| 13 | — | Design/DX 阶段跳过 | Mechanical | P3/P6 | UI 项 0 命中;内部模块 API 非开发者产品 | 跑 Design/DX |
|