docs(plan): 配置控制面阶段三工单 Opus 评审修订(REVISE→F1-F7 修回)+ F5 创始人拍档A
Some checks failed
contract-gates / contract-gates (push) Has been cancelled
docs-gate / docs-gate (push) Has been cancelled

Opus 开工前对抗评审裁 REVISE,抓三处「mock 绿真机断」硬伤,已修回:
- F1[阻断] content_json 是 routeA/routeB 嵌套信封(非扁平)——草稿编辑器定 JSON 编辑器 round-trip
  保信封(F5 创始人拍档A:schema 驱动引导表单降二期跟进)+ 前端 routeA sanity 预校验;信封契约
  取自 GenConfigContentCodec 钉入 §3.2①。
- F2[阻断] 3 个 POST(archive/recover-activating/rebroadcast)绑 @RequestParam 非 body → 前端走
  params 位否则真机 400;§二逐端点标参数位+精确字段名(freeze 用 id、activate/rollback 用
  configSetId+versionId);枚举逐字对源码核。
- F3[中高] 菜单权限种子欠定——自建 type=2 父菜单+5 按钮=6 行、id 取 7120+ 实查 max、INSERT IGNORE。
- F4 权限门用非超管角色验;F6 api 范式点名 infra/config·trade.ts 排除 genMonitor;F7 diff/漂移 VO 扁平直渲、风险 2 收窄。

Codex 半评审走异步 runtime 不可内联取,按 protocol #8 Opus 单评生效。待放行执行。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
lili 2026-07-04 23:38:12 -07:00
parent 315c18e25f
commit 37bbb5e55e

View File

@ -1,7 +1,7 @@
---
date: 2026-07-04
topic: 配置控制面-阶段三
status: 待评审(草案 · fable 列单,待 Codex+Opus 双评审 + 创始人放行执行)
status: 已 Opus 对抗评审(REVISE→F1-F7 已修回本档)· F5 创始人 2026-07-04 拍档A(JSON 编辑器基线+schema 表单二期跟进)· Codex 半评审走异步 runtime 不可内联取(protocol #8「Codex 不可用则 Opus 单评」)· 待放行执行
sot-impact: 无契约/SoT 变更 —— 消费阶段二已落的 AdminGenConfigController(/admin-api/aigc/config 十四端点),兑现运行时 SoT §5.2「管理面配置管理」早已划界的阶段三 UI;新增件全在 game-admin 前端 + 一份系统菜单/权限种子(RBAC data,非契约)
上级: docs/agent-specs/2026-07-02-配置控制面阶段二-yudao配置中心-设计.md
---
@ -14,60 +14,96 @@ sot-impact: 无契约/SoT 变更 —— 消费阶段二已落的 AdminGenConfigC
阶段三补的就是这一层:在 game-admin 里落一个配置控制台,把阶段二后端的十四个端点包成运营点得动的界面。它不引入任何新的后端能力,不改一行契约,只把已经存在的治理能力变得可视、可操作、有权限边界。
阶段二设计档(§26 界限、§66、§184/193/238)早已把这块划为「阶段三、后续出 plan」,并给了范围:浏览 / 改草稿 / 定版 / 激活 / 回滚 / 历史 / diff / 漂移对账,落点 `game-admin/src/views/wanxiang`。本工单把它落成可执行的六要素。
阶段二设计档(§26 界限、§66、§184/193/238)早已把这块划为「阶段三、后续出 plan」,并给了范围:浏览 / 改草稿 / 定版 / 激活 / 回滚 / 历史 / diff / 漂移对账,落点 `game-admin/src/views/wanxiang/config`。本工单据 Opus 开工前评审把七处硬伤/欠定修回,落成可执行的六要素。
## 二、后端已就绪的端点面(消费对象,不改)
## 二、后端已就绪的端点面(消费对象,不改;逐端点列参数位+字段名)
`AdminGenConfigController`,前缀 `/admin-api/aigc/config`,RBAC 五权限 `aigc:config:{query,save,archive,freeze,activate}`,VO 已定义。十四端点按职责分四组:
`AdminGenConfigController`,前缀 `/admin-api/aigc/config`,RBAC 五权限 `aigc:config:{query,save,archive,freeze,activate}`,VO 已定义。执行前把每个端点的**参数位与精确字段名逐字对 controller 签名 + VO 源**再核一遍(下表是评审后核过的口径,仍以源码为准):
| 组 | 端点 | 方法 | 权限 | 用途 |
| 端点 | 方法 | 参数位 | 参数/字段(逐字) | 权限 |
|---|---|---|---|---|
| 配置集 | `/page` `/get` | GET | query | 分页(按档位/状态/业务键筛)、取单集(含草稿+激活指针+状态) |
| 配置集 | `/create` `/update-draft` `/archive` | POST/PUT/POST | save/save/archive | 新建草稿、改草稿工作副本、整集归档只读 |
| 版本 | `/version/list` `/version/get` `/version/diff` | GET | query | 历史版本倒序(摘要)、取全量版本、两版 diff(prompt 变更+字节数 / 结构化旋钮拍平点路径逐项增删改) |
| 版本 | `/freeze` | POST | freeze | 把草稿快照成不可变版本行、状态转待审、不动激活指针 |
| 激活 | `/activate` `/rollback` `/recover-activating` | POST | activate | 激活某版本(双路下发)、回滚到历史激活版、恢复卡在 ACTIVATING 的集 |
| 对账 | `/reconcile` `/rebroadcast` | GET/POST | query/activate | 漂移对账(三态:同步/漂移/不可达,带容忍窗)、一键重推当前激活版 |
| `/page` | GET | query | `GenConfigSetPageReqVO`(tier/status/setKey/pageNo/pageSize) | query |
| `/get` | GET | query | `id` | query |
| `/create` | POST | **body** | `{tier, setKey, name?, description?, draftPrompt?}` | save |
| `/update-draft` | PUT | **body** | `{id, name?, description?, draftPrompt?, draftContentJson?}`(可空=不改) | save |
| `/archive` | POST | **query** ⚠ | `id`(@RequestParam,非 body) | archive |
| `/version/list` | GET | query | `configSetId` | query |
| `/version/get` | GET | query | `configSetId`, `version` | query |
| `/version/diff` | GET | query | `configSetId` + 两版本号(逐字对 controller 签名的 @RequestParam 名) | query |
| `/freeze` | POST | **body** | `{id, changeNote?}` ⚠ 用 `id``configSetId` | freeze |
| `/activate` | POST | **body** | `{configSetId, versionId}` | activate |
| `/rollback` | POST | **body** | `{configSetId, versionId}` | activate |
| `/recover-activating` | POST | **query** ⚠ | `configSetId`(@RequestParam,非 body) | activate |
| `/reconcile` | GET | query | `configSetId` | query |
| `/rebroadcast` | POST | **query** ⚠ | `configSetId`(@RequestParam,非 body) | activate |
**⚠ 三个 POST(`archive`/`recover-activating`/`rebroadcast`)绑 `@RequestParam` 而非 `@RequestBody`**:前端必须用 `request.post({ url, params })`(query 位)而非 `{ url, data }`(JSON body),否则真机 400——这在 mock 下抓不到、只在真后端炸(F2)。`freeze` 的 body 字段是 `id`(不是 `configSetId`),`activate`/`rollback``{configSetId, versionId}`,命名不一致易抄错、逐字核。
## 三、范围(MECE)
**做(本工单)**
1. **api 模块**:`game-admin/src/api/aigc/config/index.ts`——十四端点的调用封装 + 与后端 VO 对齐的 TS 类型(配置集 / 版本 / diff / 漂移报告)。
2. **控制台页面**(`game-admin/src/views/wanxiang/config/` 一组 Vue3 + Element Plus 页面,循 game-admin 既有 yudao CRUD 范式):
- **配置集列表**:分页表格(档位 cheap/tier2、状态、业务键筛选),行内「详情 / 归档」,顶部「新建配置集」。
- **配置集详情**(核心页):三区——① 草稿编辑区(prompt 大文本域 + 已知结构化旋钮的固定表单:预算 `cheap_rmb_hard_limit`/`rmb_hard_limit`、九门阈值 `gates.*`,按档位给字段;改后「保存草稿」);② 版本历史区(倒序表,列版本号/状态/激活标记/字节数,行内「查看全量 / 与上一版 diff」);③ 激活区(「定版」把草稿冻成版本 → 「激活 / 回滚」选版本下发 → 「恢复卡激活」兜 ACTIVATING)。
- **diff 视图**:两版对比——prompt 侧给「是否变更 + 两侧字节数」,结构化旋钮侧按点路径逐项列增/删/改(消费 `/version/diff` 的返回,不在前端重算)。
- **漂移对账面板**:详情页内「对账」按钮 → 展示三态报告(同步/漂移逐项/不可达),漂移态给「一键重推」。
3. **菜单 + 权限种子**:一份 SQL(循 game-cloud 既有 `system_menu` 种子范式),为五个 `aigc:config:*` 权限建菜单项 + 权限点,挂到「AIGC 治理」目录下,使超管/运营角色可见可操作。
### 3.1 api 模块 `game-admin/src/api/aigc/config/index.ts`
十四端点封装 + 与后端 VO 对齐的 TS 类型(配置集 `GenConfigSetRespVO` / 版本 `GenConfigVersionRespVO` / diff `GenConfigVersionDiffRespVO` / 漂移报告 `GenConfigDriftReportRespVO`)。
- **范式点名**:走标准 `@/config/axios`(admin-api 的 `CommonResult` 解包)——参照 `game-admin/src/api/infra/config/index.ts``src/api/wanxiang/trade.ts`。**显式排除 `src/api/wanxiang/genMonitor.ts` 作范式**:它用独立 axios 实例、裸 JSON 不带 Token 不走 CommonResult(因 gen-worker 非 CommonResult),config 端点是 admin-api CommonResult,抄 genMonitor 会解包错(F6)。
- 三个 @RequestParam POST 用 `params` 位(见 §二 ⚠)。
- 枚举常量钉死并**逐字对源码核**(下值是评审线索,executor 必核 `GenConfigSetStatusEnum``GenConfigDriftReportRespVO` 的 verdict、`GenConfigVersionDiffRespVO` 的 changeType 源):配置集状态(草稿/待审/已激活/已归档)、漂移 verdict 五态 `IN_SYNC/DRIFT/ACTIVATING_SKIPPED/NO_ACTIVE_VERSION/UNREACHABLE`、diff changeType `ADDED/REMOVED/CHANGED`
### 3.2 控制台页面 `game-admin/src/views/wanxiang/config/`(Vue3 + Element Plus,循 §3.1 点名的 yudao CRUD 范式)
- **配置集列表**:分页表格(档位 cheap/tier2、状态、业务键筛选),行内「详情 / 归档」,顶部「新建配置集」(表单 = tier/setKey/name/description/初始 draftPrompt)。
- **配置集详情**(核心页):三区——
- **① 草稿编辑区**(F1+F5 定档 A):**两个字段**——`draftPrompt`(prompt 正文大文本域,走版本行 MEDIUMTEXT 列、不进 content_json)+ `draftContentJson`(结构化旋钮的 **routeA/routeB 嵌套信封**,MVP 用**原始 JSON 编辑器**,`jsoneditor@^10.1.3` 已是 game-admin 依赖)。**编辑器铁律 = round-trip 保信封**:解析既有 `draftContentJson` → 只改目标叶子 → 原样回序列化,绝不重建成扁平结构(扁平化会丢 routeA 接线字段、激活 sanity 必拒)。保存/定版**前端先做 routeA sanity 预校验**(有 routeA 则 agentId/sessionId/session.chat_model_config 四字段[type/credential_id/model/parameters]齐全、routeA 存在则 draftPrompt 非空;至少一路 routeA/routeB),不过给红字提示、不提交(把后端 `AIGC_CONFIG_ACTIVATE_SANITY_FAILED`/`_NO_ROUTE` 提前到编辑期)。**content_json 信封契约钉此**(取自 `GenConfigContentCodec` 头注释 L23-45):
```
{ "routeA": { "agentId","sessionId",
"agent":{context_config,react_config}, // 可选透传 PATCH /agent
"session":{ "chat_model_config":{type,credential_id,model,parameters} } }, // 有 routeA 必填、整替
"routeB": { "budget.cheap_rmb_hard_limit":10.0, "gates.qpass_go_min":0.40 } } // area.key 扁平
```
- **② 版本历史区**:倒序表(版本号/状态/激活标记/content 字节数),行内「查看全量 / 与上一版 diff」;「定版」把当前草稿冻成版本(body `{id, changeNote?}`)。
- **③ 激活区**:选版本「激活 / 回滚」(body `{configSetId, versionId}`);「恢复卡激活」兜 ACTIVATING(query `configSetId`)。
- **diff 视图**:消费 `/version/diff` 返回——prompt 侧给「是否变更 + 两侧字节数」,结构化旋钮侧按 `knobChanges[]`(changeType + 点路径 + 两侧值)el-table 直渲,**前端不重算**(F7:该 VO 扁平可直渲)。
- **漂移对账面板**:详情页「对账」按钮 → `/reconcile` 三态报告(verdict 五态;漂移态列 `driftItems[]` 的 route/key/expected/actual),漂移给「一键重推」(`/rebroadcast` query `configSetId`)。
### 3.3 菜单 + 权限种子(F3:自建父菜单,别假设已有 AIGC 目录)
全仓无既有 `aigc:config` 或 AIGC 父菜单,种子须**自建**。循 `game-cloud/game-module-{biz,trade}/sql/*_menu.sql` 范式,`INSERT IGNORE` 幂等:
- **1 行 type=2 顶级/子菜单**:承载可路由页,`component=wanxiang/config/index``path`/`component_name` 按范式接线(挂到合适父目录下,或自建 AIGC 治理目录)。
- **5 行 type=3 按钮权限**:`aigc:config:{query,save,archive,freeze,activate}`
- **id 段避撞**:biz 占 7100-7107、trade 占 7110-7112 → aigc 取 **7120+**,落种子前**实查当前 `system_menu` max(id)** 再定段,别硬写撞号。
- 合计 **6 行**(1 菜单 + 5 按钮)。
**不做(划界,各自另处)**
- **schema 驱动的动态表单**(消费 AgentScope `/agent/schema` 自动渲染模型参数表单):阶段二设计档 §66 提到的形态,列为 stretch。MVP 用固定表单覆盖已知旋钮集(预算+九门阈值+模型/参数几个已知键)已够运营用;动态表单待模型参数集扩张后再接,不阻塞本工单验收。
- **BPM 审批流可视**:阶段二定「放量后启用、MVP 由创始人直接激活」,本 UI 只做直接激活路径,审批挂点留白。
- **schema 驱动引导表单**(消费 AgentScope `/agent/schema` 自动渲染):§66/§238 交付本体,**创始人 2026-07-04 拍定作二期紧随跟进**(F5),不在本期 MVP;MVP 用 §3.2① 的原始 JSON 编辑器(保信封 round-trip)覆盖,能力完整、激活可靠
- **BPM 审批流可视**:阶段二定「放量后启用、MVP 由创始人直接激活」,本 UI 只做直接激活路径。
- **阶段四观测**(trace 回放/成本对账/在跑监控/effective 配置端点):独立阶段。
- **知识件配置面**(决策6「进配置集」):范围增量,另出设计,不并入本工单。
- **知识件配置面**(决策6「进配置集」):范围增量,另出设计,不并入。
## 四、验收标准(可验证断言)
1. **构建绿**:`game-admin` `pnpm build`(或既有构建脚本)通过,新增页面无类型/lint 报错。
2. **端点全接**:十四端点每个都有 api 封装且被至少一个页面动作调用(无孤儿封装、无写死假数据)。
3. **权限门真**:五个 `aigc:config:*` 权限点在种子里定义,页面动作按权限 `v-hasPermi` 收敛(无权限的运营看不到写操作按钮);种子 SQL 可幂等重跑。
4. **一条走查闭环**(mini-desktop 真后端 + 已 seed 的 dataId,排 staging 窗口):新建配置集 → 改草稿(改一个门阈值)→ 定版 → 激活 → 详情页「对账」显示同步 → 篡改 Nacos 单键 → 「对账」显示漂移逐项 → 「一键重推」→ 复对账回同步 → 回滚到上一版。每步 UI 状态与后端返回一致。
5. **诚实口径**:走查若受 staging 部署窗口未到而只跑到 mock/本地 build 绿,如实标「真后端 e2e 待窗口」,不宣称闭环。
1. **构建绿**:`game-admin` 构建脚本通过,新增页面无类型/lint 报错。
2. **端点全接**:十四端点每个都有 api 封装且被至少一个页面动作调用(无孤儿封装、无写死假数据);三个 @RequestParam POST 确认走 params 位
3. **权限门真**(F4:**不能用超管测**——超管 `*:*:*` 全放行、证不出收敛):建一个**只勾 `aigc:config:query`** 的非超管运营角色,断言写操作按钮(新建/改草稿/定版/激活/回滚/归档/重推)全隐藏;再建一个含 save/freeze/activate 的角色断言相应按钮可见。种子 SQL 可幂等重跑。
4. **一条走查闭环**(mini-desktop 真后端 + 已 seed 的 dataId,排 staging 窗口):新建配置集 → 改草稿(JSON 编辑器改一个 `routeB` 门阈值叶子、保信封)→ 定版 → 激活 → 详情「对账」显示 `IN_SYNC` → 篡改 Nacos 单键 → 「对账」显示 `DRIFT` 逐项 → 「一键重推」→ 复对账回 `IN_SYNC` → 回滚到上一版。每步 UI 状态与后端返回一致。
5. **诚实口径**:走查若受 staging 部署窗口未到而只跑到本地 build 绿,如实标「真后端 e2e 待窗口」,不宣称闭环。
## 五、依赖与前置
- 阶段二后端(AdminGenConfigController + 治理服务 + 激活编排 + 对账)——✅ 已落 dev/2.0.0。
- game-admin 项目可构建(Vue3+Vite+Element Plus yudao fork)——执行前先 `pnpm i` + 一次基线 build 确认环境。
- 阶段二后端(AdminGenConfigController + 治理服务 + 激活编排 + 对账 + `GenConfigContentCodec` 信封契约)——✅ 已落 dev/2.0.0。
- game-admin 项目可构建(Vue3+Vite+Element Plus yudao fork;`jsoneditor` 已在依赖)——**执行第一步`pnpm i` + 一次基线 build 确认环境**,不在坏环境上叠业务代码
- 真后端走查依赖 game-cloud 部署带本子域(`aigc:config` 权限种子进库)+ AgentScope Service 在跑——排 staging/部署窗口,可逆动作免逐次请示、live 变更逐次报。
## 六、风险与回滚
- **风险 1:game-admin 环境未就绪**(依赖装不上/基线 build 不过)。缓解:执行第一步先跑基线 build,不过则先修环境再动业务代码,不在坏基线上叠加。
- **风险 2:VO↔TS 类型漂移**(前端手写类型与后端 VO 对不上)。缓解:类型逐字对着 controller 的 ReqVO/RespVO 抄,diff/漂移报告这类嵌套结构尤其对齐;走查断言 4 兜真实字段。
- **风险 1(最高,F1):content_json 信封被前端扁平化**——JSON 编辑器若不 round-trip 保 routeA/routeB 信封,序列化出的配置激活 sanity 必拒。缓解:§3.2① 铁律(解析→改叶子→原样回序列化)+ 前端 routeA 预校验 + 走查断言 4 用真后端激活兜真。
- **风险 2(中,F2):三个 @RequestParam POST 用错参数位**——mock 抓不到、真机 400。缓解:§二 ⚠ 逐端点标位;api 封装评审时核这三个走 `params`
- **风险 3(降级,F7):diff/漂移 VO 前端渲**——原担忧其嵌套,实为扁平可直渲,精力压到风险 1,不在此处过度设计。
- **回滚**:纯前端新增 + 一份可幂等种子,无存量改动;回滚 = 撤页面 + 撤菜单种子行,零运行时影响(后端端点本就存在、不因 UI 撤而变)。
## 七、执行方式
fable 列此工单;执行按现行分工——创始人驱动 opus 会话(plan 模式 + goal/ultracode 自治自审),或经全自主授权由 fable 派 opus 隔离执行、逐波终审(hash/父链/构建亲跑/走查证据)。worktree 隔离须注意:本仓 worktree 默认基线是 dev/1.0.0(TS monorepo 老线、无 game-admin),执行前必须先 reset 到 dev/2.0.0 tip(见 tech-decisions §14 坑④)
fable 列此工单并按 protocol #8 过 Opus 开工前对抗评审(REVISE→本档已修 F1-F7);F5 范围项创始人已拍。执行按现行分工——创始人驱动 opus 会话(plan 模式 + goal/ultracode 自治自审),或经全自主授权由 fable 派 opus 隔离执行、逐波终审(build 亲跑 + 走查证据)。**worktree 隔离铁律**:本仓 worktree 默认基线是 dev/1.0.0(TS monorepo 老线、无 game-admin),执行前**必须先 `git reset --hard <dev/2.0.0 tip>``git checkout -b work <tip>`** 再动手(见 tech-decisions §14 坑④),并自查 `game-admin/` 存在