docs(agent-specs): 配置控制面阶段二设计 双评审 11 条全修收口(激活降账本语义+失败即时补偿重放/namespace 口径前置/值域 sanity 校验/路B dataId 按档隔离/hash 引证改真实 feat 提交)+ 两板对账
Some checks failed
docs-gate / docs-gate (push) Has been cancelled
Some checks failed
docs-gate / docs-gate (push) Has been cancelled
Codex 2B+5M / Opus 0B+2M+4m 合并清单全采纳;独立终验:签名短语计数正常、新引 hash rev-parse 为真、docs-gate 七检绿。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
9fcfe61a0a
commit
f91dffa267
@ -2,14 +2,14 @@
|
||||
date: 2026-07-02
|
||||
topic: 配置控制面-阶段二
|
||||
status: 草稿 · 创始人已拍方向 B(维持 yudao⊕Nacos;prompt 移出 Nacos→MySQL 版本行,2026-07-02)· 待 Codex+Opus 双评审 → 创始人评审
|
||||
sot-impact: 修订 生成引擎运行时(SoT §5.2 管理面配置管理 / §5.8 配置三类"受治理发版" / ADR-4 配置热取 / A13 配置注册表:把 GitOps/Langfuse 式口径收敛为 yudao 配置中心版本化(版本账本落 MySQL 版本行)+ 双路激活,与上级设计 §6 pending 同一收口面,收口时回写;对上级设计两处口径的回调挂账见本档 §7)
|
||||
sot-impact: 修订 生成引擎运行时(SoT §5.2 管理面配置管理 / §5.8 配置三类"受治理发版" / ADR-4 配置热取 / A13 配置注册表:把 GitOps/Langfuse 式口径收敛为 yudao 配置中心版本化(版本账本落 MySQL 版本行)+ 双路激活,与上级设计 §6 pending 同一收口面,收口时回写;对上级设计四处口径 + SoT 回写的回调挂账见本档 §7)
|
||||
上级: docs/agent-specs/2026-06-30-配置控制面一次性按序实现-设计.md
|
||||
关联:
|
||||
- 阶段前置(已落地):阶段〇 生产基建(Nacos 2.4.3 / RocketMQ 5.3.1 / Sentinel 自托管 mini-infra + game-cloud 接入,`docs/plans/2026-07-01-配置控制面-spike与阶段〇生产基建-plan.md`)· 阶段一① 护城河 middleware(`07100eef`)· 阶段一② cheap-worker 归并 Service `/chat`(`526e9b3d`)
|
||||
- 阶段前置(已落地):阶段〇 生产基建(Nacos 2.4.3 / RocketMQ 5.3.1 / Sentinel 自托管 mini-infra + game-cloud 接入,`docs/plans/2026-07-01-配置控制面-spike与阶段〇生产基建-plan.md`)· 阶段一① 护城河 middleware(实施 plan 档 `07100eef`;代码落地 = feat 提交 `55162341`/`e9c7a3bb`/`c2661719`,统一门判 GateJudgment + 续修 RepairMiddleware + 软预算软停)· 阶段一② cheap-worker 归并 Service `/chat`(实施 plan 档 `526e9b3d`;代码落地 = feat 提交 `e9e7006c`/`1662eb0d`,九门判据 run_cheap_gates + 独立 Service 壳 build_cheap_app)
|
||||
- tier2/gen-worker/worker/genconfig.py(进程内配置门面 `get(area,key,default)`,现读本地 `tier2/config/generation.yaml`;本阶段把其读取后端提升到 Nacos)
|
||||
- tier2/gen-worker/worker/nacos_hotconfig.py(阶段〇 D2 已建、未接线;本阶段接进 genconfig 作热源)
|
||||
- tier2/gen-worker/worker/middleware.py:173(CircuitBreakerMiddleware 软预算,预算/阈值经 genconfig 读)· worker/gate_judge.py(门判 GateJudgment)
|
||||
- tier2/gen-worker/worker/store.py(MySQL manifest + MinIO 源文件的成品归档 —— MinIO 在本项目的既有角色参照,§3.1 prompt 存储选型佐证)· cheap-worker/cheap_roles.py ≈30KB / tier2 worker/roles.py ≈24KB(prompt 尺寸画像依据)
|
||||
- tier2/gen-worker/worker/store.py(成品源工程归档的后端 seam:BackendStore 定义 MySQL manifest + MinIO 源文件接口、当前为占位,真正在用的是 LocalFsStore 本地实现 —— §3.1 prompt 存储选型佐证)· cheap-worker/cheap_roles.py 30499B(≈30KB)/ tier2 worker/roles.py 24539B(≈24KB)/ contracts/prompts/04-config/cheap-system.md 14695B(≈14.7KB,外置 prompt 最大单条)(prompt 尺寸画像依据)
|
||||
- cheap-worker/cheap_service_app.py:213(`_cheap_middlewares_factory` 每回合工厂)· :300(`build_cheap_app`)
|
||||
- tier2/gen-worker/service/app.py(AgentScope Service `/chat` + `/agent` + `/session`)
|
||||
- agentscope==2.0.2:app/_router/_agent.py:138(`update_agent` PATCH)· app/_router/_session.py:291(`update_session` PATCH,部分字段更新语义)
|
||||
@ -71,17 +71,17 @@ sot-impact: 修订 生成引擎运行时(SoT §5.2 管理面配置管理 / §5.8
|
||||
|
||||
### 3.1 配置中心的两半:yudao 治理与版本账本 ⊕ Nacos 生效下发
|
||||
|
||||
配置中心把职责劈成两半,各用现货、不自建机器。**yudao 管治理与版本账本**:编辑的鉴权、`creator` 归因、放量后的 BPM 审批、激活状态机、操作审计,连同每次定版落下的版本行——权限、审计、CRUD 全是 yudao 作为成熟后台框架的原生件,game-cloud 是它的 fork,拿来即用。**Nacos 管生效下发**:长轮询推送、客户端磁盘快照兜底、命名空间隔离——这些是 Nacos 打磨多年的下发机器,阶段〇已自托管进 mini-infra,预算/门阈值那一路的热推全靠它(路 B,见 §3.3)。
|
||||
配置中心把职责劈成两半,各用现货、不自建下发机制。**yudao 管治理与版本账本**:编辑的鉴权、`creator` 归因、放量后的 BPM 审批、激活状态机、操作审计,连同每次定版落下的版本行——权限、审计、CRUD 全是 yudao 作为成熟后台框架的原生件,game-cloud 是它的 fork,直接复用。**Nacos 管生效下发**:长轮询推送、客户端磁盘快照兜底、命名空间隔离——这些是 Nacos 成熟的下发通道,阶段〇已自托管进 mini-infra,预算/门阈值那一路的热推全靠它(路 B,见 §3.3)。
|
||||
|
||||
版本账本落 MySQL 而不落 Nacos,被三个事实定死,第一个就是创始人拍 B 时点名要解的:
|
||||
版本账本落 MySQL 而不落 Nacos,基于三个约束确定,第一个就是创始人拍 B 时点名要解的:
|
||||
|
||||
- **prompt 正文放不进 Nacos**。Nacos 单配置内容默认上限 100KB(容量保护 `defaultMaxSize`),而本仓一个角色的 prompt 源就有几十 KB(`cheap_roles.py` ≈30KB、tier2 `roles.py` ≈24KB),配置集版本再带 few-shot 与参数,内容会向上限爬。把最大、改得最勤的旋钮放在一条 100KB 的钢丝上,不如一开始就换地方。
|
||||
- **prompt 正文放不进 Nacos**。Nacos 单配置内容默认上限 100KB(容量保护 `defaultMaxSize`)。prompt 的实际规模有两个量级:Python 角色源文件(`cheap_roles.py` 30499B、tier2 `roles.py` 24539B,含多角色内置 prompt 与配套代码,非单条运行时 prompt)与外置 prompt 文件(`contracts/prompts/04-config/cheap-system.md` 14695B 为当前最大单条、tier2 最大单条 `writer-system.md` 4970B)。单条运行时 prompt 现在离 100KB 尚有余量,但配置集版本要把一档的 system_prompt 连同 few-shot、多角色配置一起收进一行,内容会随 few-shot 与角色规模增长向上限爬。把最大、改得最勤的旋钮放在接近 Nacos 单配置上限的位置,不如一开始就换地方。
|
||||
- **定版要原子**。版本行(元数据 + 全量内容)同库同事务一次落;内容若在库外,定版就成了跨系统写,要补超时/重试/补偿——治理层最高频的动作不该是分布式事务。而 prompt 一旦出 Nacos,版本若劈成"prompt 在 MySQL、小参在 Nacos"两处,一次定版跨两系统、必漂移,所以账本整体落 MySQL。
|
||||
- **diff 与检索要就地**。版本 diff、按内容查历史都是版本行上的本地操作;内容在外部系统则每次 diff 都要来回取对象。
|
||||
|
||||
**prompt 内容列定 MySQL `MEDIUMTEXT`,不选 MinIO**——在此定死、不留开放项。MinIO 在本项目的既有角色是成品源工程归档(`store.py`:MySQL manifest + MinIO 源文件、内容哈希、id+version 寻址),那是"多文件源树"的形状;prompt 是"一段文本字段"的形状,几 KB 到几十 KB,MinIO 的价值(大对象、二进制、流式)一样都用不上,却把定版原子性与就地 diff 全破掉,还把备份从"一份 MySQL dump = 治理+内容一致快照"劈成两个系统。列型取 `MEDIUMTEXT`(16MB)而非 `TEXT`(64KB):30KB 级 prompt 加 few-shot 有越过 64KB 的现实可能,MEDIUMTEXT 给足余量且无额外成本。
|
||||
**prompt 内容列定 MySQL `MEDIUMTEXT`,不选 MinIO**——在此确定、不留开放项。MinIO 在本项目的设计定位是成品源工程归档的后端 seam(`store.py` 的 BackendStore 声明 MySQL manifest + MinIO 源文件、内容哈希、id+version 寻址,目前是接口占位,真正在用的是 LocalFsStore 本地文件实现),那是"多文件源树"的形状;prompt 是"一段文本字段"的形状,几 KB 到几十 KB,MinIO 的价值(大对象、二进制、流式)一样都用不上,却把定版原子性与就地 diff 全破掉,还把备份从"一份 MySQL dump = 治理+内容一致快照"劈成两个系统。列型取 `MEDIUMTEXT`(16MB)而非 `TEXT`(64KB):30KB 级 prompt 加 few-shot 有越过 64KB 的现实可能,MEDIUMTEXT 给足余量且无额外成本。版本表的实现约束一并明确:表用 `InnoDB + DEFAULT CHARSET=utf8mb4`;prompt 正文列不建全文或普通索引(只做整行读写、不参与检索),另存 `content_hash` 与 `content_bytes` 两列供快速比对与容量核对(`content_bytes` 按 utf8mb4 字节数计,防混淆字符数与字节数);备份恢复以包含版本行正文的 MySQL dump / binlog 为口径,而非只抽结构不抽内容;两版 diff 在应用层做。
|
||||
|
||||
对上级设计"自建版本表 = 重造 Nacos"的判定要诚实交代:那条针对的是**版本化下发机器**(推送/快照/回滚/灰度),这部分仍然全买——路 B 热推是 Nacos、基建配置通路是 Nacos SCA;挪回 MySQL 的只是**版本行**这张普通 yudao 业务表,借的全是 yudao CRUD/分页/审计原生能力,没有一行自建机器。此口径回调上级 §3.3 等处,挂账见 §7。
|
||||
对上级设计"自建版本表 = 重造 Nacos"的判定要诚实交代:那条针对的是**版本化下发机制**(推送/快照/回滚/灰度),这部分仍然全买——路 B 热推是 Nacos、基建配置通路是 Nacos SCA;挪回 MySQL 的只是**版本行**这张普通 yudao 业务表,借的全是 yudao CRUD/分页/审计原生能力,没有一行自建下发机制。此口径回调上级 §3.3 等处,挂账见 §7。
|
||||
|
||||
于是四方各就各位:
|
||||
|
||||
@ -90,7 +90,7 @@ sot-impact: 修订 生成引擎运行时(SoT §5.2 管理面配置管理 / §5.8
|
||||
- **AgentScope Service 的 Redis**:路 A(prompt/模型/参数)生效投影(激活时 PATCH 写入,每 POST 现装配读出;Service 只认自己的 Redis、不认 Nacos,所以路 A 生效只能靠 PATCH)。
|
||||
- **worker 进程内 genconfig**:路 B 生效投影(经 NacosHotConfig 从 Nacos 热读)。
|
||||
|
||||
账本单点(MySQL 版本行)、投影两处(Redis / Nacos 生效 dataId)、消费两路(Service per-POST / middleware 构造)——权威与投影的关系一眼可查,§3.6 的漂移对账就建在这上面。
|
||||
账本单点(MySQL 版本行)、投影两处(Redis / Nacos 生效 dataId)、消费两路(Service per-POST / middleware 构造)——权威与投影的关系清晰,§3.6 的漂移对账就建在这上面。
|
||||
|
||||
### 3.2 配置对象与生命周期:改 → 版本 → 审核 → 激活 → 回滚
|
||||
|
||||
@ -131,18 +131,24 @@ flowchart LR
|
||||
ACT -- "记当前激活版 + 操作日志" --> YU[("yudao 治理表")]
|
||||
```
|
||||
|
||||
- **路 A(prompt/模型/参数)**:激活编排把内容 PATCH 进 AgentScope Service 的 `/agent`(system_prompt / 压缩比例 / tool_result 截断 / max_iters)与 `/session`(模型 / 协议 type / credential / max_tokens / thinking / reasoning_effort / temperature)。`/session` 的 PATCH 是部分字段更新语义,只改本次带上的字段。写进 Service 的 Redis 后,下一个 POST `/chat` 现装配即生效。
|
||||
- **路 B(软预算目标 / 门阈值)**:这些参数不在 `/agent`+`/session` 里,它们是 worker 的 middleware 在构造时从 genconfig 读的。激活编排把内容 publish 进 worker 监听的 Nacos 生效 dataId,NacosHotConfig 经长轮询推送热读进进程内,genconfig 从它取到新值,下一次 middleware 构造时读到。
|
||||
- **路 A(prompt/模型/参数)**:激活编排把内容 PATCH 进 AgentScope Service 的 `/agent`(system_prompt / 压缩比例 / tool_result 截断 / max_iters)与 `/session`(模型 / 协议 type / credential / max_tokens / thinking / reasoning_effort / temperature)。`/session` 的 PATCH 在顶层是部分字段更新语义(`exclude_unset`,只改本次带上的顶层字段),但模型与参数都封在 `chat_model_config` 这一个子对象里,而该子对象一旦出现即被**整体替换**——顶层 `exclude_unset` 不深合并它内部的 `parameters`,且 `type`/`model` 是必填字段。所以激活编排改任一模型参数(哪怕只动 max_tokens 或 thinking)都必须从版本行组装出完整的 `chat_model_config`,把 `type`/`credential_id`/`model`/`parameters` 全带齐,不能只发局部对象,否则未带上的字段会被清空。写进 Service 的 Redis 后,下一个 POST `/chat` 现装配即生效。
|
||||
- **路 B(软预算目标 / 门阈值)**:这些参数不在 `/agent`+`/session` 里,它们是 worker 的 middleware 在构造时从 genconfig 读的。激活编排把内容 publish 进 worker 监听的 Nacos 生效 dataId,NacosHotConfig 经长轮询推送热读进进程内,genconfig 从它取到新值,下一次 middleware 构造时读到。这里有一处 dataId 粒度要定死:cheap-worker 与 tier2 gen-worker 是两个独立进程、各接一个 NacosHotConfig,两档 key 命名本就不同(cheap 用 `cheap_rmb_hard_limit`、tier2 用 `rmb_hard_limit`)。**路 B 生效 dataId 按档隔离**——cheap 与 tier2 各用一个专属 dataId,而不是共用一个 `gen-hot-params` 整体替换;否则激活一档的配置集会把另一档的 key 从该 dataId 上冲掉(publish 是整内容替换,worker 初读/重启即缺 key)。激活哪一档,就只 publish 那一档的 dataId。
|
||||
|
||||
**为什么静默期语义在这个模型下几乎是自然的**:两路生效都发生在"下一次生成"的边界上——路 A 的 Redis 在 `/chat` 进 session 锁之前读、路 B 的 genconfig 在 middleware 构造时读,正在跑的那一局早已经读过配置了,新配置只影响此后新起的 POST。所以真正的撕裂窗口只剩一个:一个配置集的多次 PATCH/publish 之间非原子,理论上并发一局能读到"路 A 新、路 B 旧"的组合。MVP 单操作者 + 创作页置灰把这个窗口的影响面压到零,取静默期语义即可;真机制级原子留放量后(上级 §3.3)。激活编排对此的硬要求是:一批下发须**幂等**、**失败即整批判未生效可重试**、不留半生效态(见 §3.6 失败模式)。
|
||||
**为什么静默期语义在这个模型下几乎是自然的**:两路生效都发生在"下一次生成"的边界上——路 A 的 Redis 在 `/chat` 进 session 锁之前读、路 B 的 genconfig 在 middleware 构造时读,正在跑的那一局早已经读过配置了,新配置只影响此后新起的 POST。所以并发引起的撕裂窗口只剩一个:一个配置集的多次 PATCH/publish 之间非原子,理论上并发一局能读到"路 A 新、路 B 旧"的组合。MVP 单操作者 + 创作页置灰把这个并发窗口的影响面压到零,取静默期语义即可;真机制级原子留放量后(上级 §3.3)。
|
||||
|
||||
还有一个撕裂窗口不是并发引起、静默期也兜不住,要如实交代:**激活自身中途失败**。双路投影是"写即被读"——PATCH 写进 Redis 即被下一 POST 装配,publish 进 Nacos 即被 worker 长轮询推送读到,两路之间没有分布式事务。若激活先成功下发一路、再在另一路失败,已发出的那一路在投影层已经生效、不会自动回退;此刻"当前激活版指针不前移"只保住**账本**语义(见 §3.6),保不住投影。所以本设计不写"绝不留半生效态"这种投影层做不到的强承诺,而是要求激活编排在任一路失败时**立即补偿**:把已成功下发的那一路重推回上一激活版的内容(配置中心持有上一版,可做),不等定期对账。激活编排对此的硬要求是:一批下发须**幂等**、**任一步失败即整批判未生效、立即把已成功路补偿重推回上一激活版、再标为可重试**(见 §3.6 失败模式)。
|
||||
|
||||
### 3.4 NacosHotConfig 接进 genconfig(阶段〇 follow-up 落地)
|
||||
|
||||
预算/门阈值那一路的热读,是把 `nacos_hotconfig.py` 接进既有的 genconfig 门面,而不是改 middleware。现状链条是 `middleware → genconfig.get("budget", "rmb_hard_limit") → generation.yaml`;genconfig 已经是一个带缓存、带 best-effort 兜底、带内置默认的成熟门面,middleware 到处在调它。阶段二只换 genconfig 的**读取后端**:让它优先读 NacosHotConfig(配置中心激活投影),读不到回落本地 `generation.yaml`,再回落内置默认。
|
||||
预算/门阈值那一路的热读,是把 `nacos_hotconfig.py` 接进既有的 genconfig 门面,而不是改 middleware。现状链条是 `middleware → genconfig.get("budget", "rmb_hard_limit")`,genconfig 现有取值优先级是 **env 覆盖 > 外部 `generation.yaml` > 内置默认 > 调用方 default**;它已经是一个带缓存、带 best-effort 兜底、带内置默认、支持 env 单点覆盖的进程内配置门面,middleware 到处在调它。阶段二只换 genconfig 的**读取后端**:把 NacosHotConfig(配置中心激活投影)接成新的热源。
|
||||
|
||||
这样接线有三处好处。其一,**middleware 一行不改**:`genconfig.get(...)` 的调用面完全不动,CircuitBreakerMiddleware 的软预算目标、门判的阈值都自动吃上 Nacos 热读。其二,**回落链天然是 fail-safe**:Nacos 不可达时 NacosHotConfig 自带本地磁盘快照兜底,再不行 genconfig 回落本地 YAML 与内置默认,生成主链不被配置中心连累。其三,**尊重既有 working code**:genconfig 是雏形阶段就在的进程内配置层(SoT §5.2 提到的那个雏形),阶段二是把它的源从本地文件提升到集中版本化,不是推翻重造。
|
||||
接入后 Nacos 热源与 env 的相对优先级必须定死、不能留空:**Nacos 热源 > env > 外部 YAML > 内置默认 > 调用方 default**。理由是配置中心才是权威,机器上遗留的实验 env 不应静默压过激活值——否则会出现"配置中心已激活、机器上却不生效"的难查故障(操作者在配置中心看不到机器上的 env)。env 由现状的最高优先级降为"Nacos 取不到时"的回落层之一,保留其一次性实验逃生舱的作用;同时把 env 覆盖纳入 §3.6 漂移对账口径:对账发现某旋钮实际生效值来自 env 而非当前激活版时,一并告警。
|
||||
|
||||
命名空间上有一个已知的坑必须钉死:**Nacos 默认公共空间的 namespaceId 是空串,不是字面量 "public"**(阶段〇 follow-up 明确)。业务生成配置的 dataId 要么显式放进一个专门的命名空间(用真实 namespaceId、不是 "public" 三个字母),要么明确用空串走默认空间;写侧(yudao publish)与读侧(worker NacosHotConfig 订阅、game-cloud SCA)必须对齐同一个真实 namespaceId,否则激活写进一个空间、worker 在另一个空间读、配置永远推不到。
|
||||
这样接线有三处好处。其一,**middleware 一行不改**:`genconfig.get(...)` 的调用面完全不动,CircuitBreakerMiddleware 的软预算目标、门判的阈值都自动吃上 Nacos 热读。其二,**回落链天然是 fail-safe**:Nacos 不可达时 NacosHotConfig 自带本地磁盘快照兜底,再不行 genconfig 回落 env、本地 YAML 与内置默认,生成主链不被配置中心连累。此外 NacosHotConfig 侧要补一道值 fail-safe:它现在只挡空/脏 JSON、不校验业务范围,一个合法 JSON 但语义非法的值(负预算、超小超时)会直接 update 进热参;要改成遇语义非法值时**保留旧值 + 告警、不覆盖当前热参**,把错值挡在生成链之外(激活前的正向值域校验见 §3.6)。其三,**尊重既有 working code**:genconfig 是雏形阶段就在的进程内配置层(SoT §5.2 提到的那个雏形),阶段二是把它的源从本地文件提升到集中版本化,不是推翻重造。
|
||||
|
||||
命名空间上有一个已知的坑必须先解:**Nacos 默认公共空间的 namespaceId 是空串,不是字面量 "public"**(阶段〇 follow-up 明确)。业务生成配置的 dataId 要么显式放进一个专门的命名空间(用真实 namespaceId、不是 "public" 三个字母),要么明确用空串走默认空间;写侧(yudao publish)与读侧(worker NacosHotConfig 订阅、game-cloud SCA)必须对齐同一个真实 namespaceId,否则激活写进一个空间、worker 在另一个空间读、配置永远推不到。
|
||||
|
||||
这不止是一句提醒,而是一项**阶段二必修前置任务**:现状代码里 namespace 口径已经与"空串"这一事实不一致——Java `game-cloud/huijing-server/.../application.yaml` 两处写 `namespace: public`、Python `tier2/gen-worker/service/nacos_registry.py` 默认 `os.environ.get("NACOS_NAMESPACE", "public")`、`test_nacos_registry.py` 还断言 `"public"`。若阶段二写侧按空串、读侧沿用 `public`,路 B 会静默推不到。所以在接线动作之前先统一口径:走默认公共空间就把该配置项置空/删除、而不是填字面量 `"public"`,并同步改 Java 配置、Python 默认值、对应测试断言与凭据档(`docs/内网凭据与端点.md`)。这一步排在步骤 4 接线之前(见 §4)。
|
||||
|
||||
### 3.5 分工边界:基建配置 vs 业务生成配置
|
||||
|
||||
@ -164,16 +170,18 @@ flowchart LR
|
||||
|
||||
激活是一批跨系统的非原子写(PATCH Service + publish Nacos + 更新 yudao 指针),这里的失败模式要正面处理,不能让配置中心把生成链路带崩。
|
||||
|
||||
- **激活失败可重试、不留半生效态**。一批下发里任一步失败(某个 PATCH 返错、Nacos publish 超时),整批判**未激活**:yudao 的当前激活版指针**不前移**,保留上一激活版为权威,并把这次激活标为失败可重试。下发动作须幂等(同一版本重放不产生副作用),重试就是把整批重放一遍。绝不出现"指针已前移、但 Service 只 PATCH 了一半"的状态。
|
||||
- **Service 不可达**。路 A 依赖 Service 在线才能 PATCH。Service 不可达时,激活判失败(同上),保留上一激活版;此时 Service 上跑的还是它 Redis 里的旧配置,生成不中断,只是新配置没生效。Service 恢复后重放激活即可。
|
||||
- **配置漂移检测**。Service 的 Redis 投影可能与"当前激活版"漂移——Service 重启若 Redis 未持久化会丢配置回落缺省、或有人绕过治理直接改了 Redis/Nacos、或某次激活 PATCH 部分失败没被发现。配置中心提供一个对账:激活后与定期,拉 Service 的 `/agent`+`/session` 当前配置、比对当前激活版的路 A 内容;拉 worker 的生效投影、比对路 B 内容;对不上即告警,并支持一键重推(重放激活把投影拉回激活版)。这道对账是"配置中心为权威、Service 与 worker 为投影"这个定位的兜底闸。
|
||||
- **命名空间错配**。见 §3.4:写读两侧的 namespaceId 必须是同一个真实值,默认空间是空串非 "public"。这条在接线时一次性核对钉死,避免配置静默推不到。
|
||||
- **激活失败即时补偿(账本语义,不作投影强承诺)**。一批下发里任一步失败(某个 PATCH 返错、Nacos publish 超时),整批判**未激活**:yudao 当前激活版指针**不前移**,保留上一激活版为账本权威。但双路投影是"写即被读"、两路间无事务,已成功下发的那一路在投影层已经生效——指针不前移只保住账本、保不住投影。所以失败处置不能停在"判未激活",必须**立即补偿**:把本批已成功下发的那一路(PATCH 或 publish)重推回上一激活版的内容,再标为可重试。补偿与重放都要幂等(同一版本重推无副作用)。这样账本与投影一起收敛回上一激活版,不留"路 A 新、路 B 旧"的持续撕裂;而不是把"绝不留半生效态"写成投影层做不到的强承诺、再靠定期对账慢慢兜。
|
||||
- **MySQL 不可达 / 指针写失败**。激活还含"读版本行、写激活尝试、前移当前激活版指针、记审计"这几步 yudao 库内写,两种情形分开处置:(a) 起步读版本行时 MySQL 不可达——直接拒绝激活、不发起任何下发,生成继续用旧投影。(b) 三路投影(PATCH `/agent`、PATCH `/session`、publish Nacos)都成功、最后前移指针或写审计时 MySQL 失败——此刻投影已是新版、账本仍指旧版,是确定漂移。处置:激活状态先持久化为 `ACTIVATING`(下发前落、全部成功后才转 `ACTIVE`),恢复任务按激活尝试幂等地二选一执行到底——要么补提交指针(投影既已是新版,对齐账本),要么补偿重推旧版回投影并回滚该尝试,不停在中间态。
|
||||
- **配置值本身非法(合法但语义错)**。激活链是"改 → 定版 → 激活",对预算写错单位(元/分混)、预算填成天文数、超时给到过小、`max_tokens ≤ thinking_budget`、模型协议 type 与 credential type 不匹配这类**类型正确但语义错**的值,若无校验会一路激活、下一局生效——预算是成本红线旋钮,配错直接让软预算失效、成本超支。所以激活前加一道**值域 sanity 校验**:预算为正数且落在合理区间、单位固定;超时有下限;`max_tokens > thinking_budget`;模型协议 type 与 credential type 匹配;prompt 非空。校验不过直接拒绝激活。NacosHotConfig 读侧再兜一道(§3.4:语义非法值保旧值 + 告警);仍漏过的错值挂阶段四观测(成本异常告警)事后发现。
|
||||
- **Service 不可达**。路 A 依赖 Service 在线才能 PATCH。Service 不可达时激活判失败,按上面的补偿口径处置(路 A 尚未成功、无需补偿路 A;若路 B 已 publish 成功则补偿重推路 B 回旧版),保留上一激活版;Service 上跑的还是它 Redis 里的旧配置,生成不中断,只是新配置没生效。Service 恢复后重放激活即可。
|
||||
- **配置漂移检测**。Service 的 Redis 投影可能与"当前激活版"漂移——Service 重启若 Redis 未持久化会丢配置回落缺省、或有人绕过治理直接改了 Redis/Nacos、或某次激活部分失败没补偿干净、或机器上遗留 env 压过了本该生效的激活值。配置中心提供一个对账:激活后与定期,拉 Service 的 `/agent`+`/session` 当前配置比对当前激活版的路 A 内容;拉 worker 的生效投影比对路 B 内容(含 env 覆盖口径:实际生效值来自 env 而非激活版时也算漂移);对不上即告警,并支持一键重推(重放激活把投影拉回激活版)。这道对账是"配置中心为权威、Service 与 worker 为投影"这个定位的兜底闸,但不是失败的第一道防线——第一道是上面的即时补偿。
|
||||
- **命名空间错配**。见 §3.4:写读两侧的 namespaceId 必须是同一个真实值,默认空间是空串非 "public",且现状代码的 `public` 字面量偏差要作前置任务先修。这条在接线时一次性核对确认,避免配置静默推不到。
|
||||
|
||||
## 4 步骤计划
|
||||
|
||||
(阶段序 SVG 待补)
|
||||
|
||||
阶段二自身按依赖分五步串行;阶段三(UI)、阶段四(观测)作为后续阶段划界在后,各自后续出 plan。
|
||||
阶段二自身按依赖分五步串行,另有一项 namespace 口径统一作为接线前置;阶段三(UI)、阶段四(观测)作为后续阶段划界在后,各自后续出 plan。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
@ -186,6 +194,11 @@ flowchart LR
|
||||
N3 --> N4[阶段四 观测<br/>后续出 plan]
|
||||
```
|
||||
|
||||
**前置 · namespace 口径统一**(排在步骤 4 接线之前)
|
||||
- 交付:把现状代码里的 `namespace: public` 字面量偏差统一成同一个真实 namespaceId(走默认公共空间就置空、而非填 "public"),覆盖 Java `application.yaml`(两处)、Python `nacos_registry.py` 默认值、`test_nacos_registry.py` 断言与凭据档 `docs/内网凭据与端点.md`(见 §3.4)。
|
||||
- 验证:写侧(yudao publish)与读侧(worker NacosHotConfig、game-cloud SCA)落在同一真实 namespaceId;既有服务发现/注册不回归。
|
||||
- 风险:不先修这项,路 B 写读会静默错空间、步骤 4 接线无从验证。
|
||||
|
||||
**步骤 1 · 配置集建模 + yudao 治理骨架**
|
||||
- 交付:在 game-module-aigc 落一个生成配置治理子域(复用 yudao 的鉴权/creator/审计框架,不塞进 infra_config 的 KV 表——生成配置是结构化配置集、不是键值对)。定义配置集的数据模型(一个配置集含哪些旋钮、映射到哪些 `/agent`+`/session` 字段与哪些 Nacos 生效 key)、版本与当前激活版指针、生命周期状态机、creator 与操作审计。
|
||||
- 验证:能建/改/定版一个配置集,creator 与时间随版本落库;权限门挡住无权写;状态机流转符合 §3.2。
|
||||
@ -194,21 +207,21 @@ flowchart LR
|
||||
|
||||
**步骤 2 · 版本行与历史(MySQL)**
|
||||
- 交付:定版落版本行——配置集全量内容(prompt 存 `MEDIUMTEXT` + 模型/参数/预算/阈值)与元数据同库同事务一次写成一行;历史列表、任一历史版取回、两版 diff;当前激活版指针只由激活动作前移(定版不动它)。
|
||||
- 验证:定多版后能列历史、取任一版、diff 两版;定版是单库事务、无跨系统写;30KB 级 prompt 正文完整存取无截断。
|
||||
- 验证:定多版后能列历史、取任一版、diff 两版;定版是单库事务、无跨系统写;30KB 级 prompt 正文完整存取无截断,并加一个 **64KB 边界样本**(越过 `TEXT` 上限、验证 `MEDIUMTEXT` 存取无截断)与 **utf8mb4 字节数校验**(`content_bytes` 按字节而非字符计,含多字节中文/emoji 时口径正确)。
|
||||
- 依赖:步骤 1。
|
||||
- 风险:版本行只增不删,量级 = 人工定版频次(每天几次),多年不清理也只是几千行——留一个归档策略位即可,不做提前优化。
|
||||
|
||||
**步骤 3 · 双路激活编排**
|
||||
- 交付:激活动作把选定版双路下发——路 A PATCH `/agent`+`/session`,路 B publish 进 worker 监听的生效 dataId;更新当前激活版指针 + 记操作日志;成组下发幂等、失败整批判未生效可重试(见 §3.6);静默期语义(只对下一批新生成生效)。
|
||||
- 验证:改任一旋钮 → 定版 → 激活 → 下一次生成生效;并发两局不读到路 A 新/路 B 旧的撕裂组合(静默期);回滚旧版即恢复;一批下发中途失败时指针不前移、可重试。
|
||||
- 交付:激活动作先做值域 sanity 校验(§3.6),通过后把选定版双路下发——路 A PATCH `/agent`+`/session`(模型/参数从版本行组装完整 `chat_model_config`,§3.3),路 B publish 进 worker 监听的按档隔离生效 dataId;更新当前激活版指针 + 记操作日志;成组下发幂等、任一步失败即整批判未生效并立即补偿重推已成功路回上一激活版、再判可重试(见 §3.6);静默期语义(只对下一批新生成生效)。
|
||||
- 验证:改任一旋钮 → 定版 → 激活 → 下一次生成生效;并发两局不读到路 A 新/路 B 旧的撕裂组合(静默期);回滚旧版即恢复;一批下发中途失败时指针不前移、已成功路被补偿重推回旧版、可重试;非法值(负预算等)在激活前被拒。
|
||||
- 依赖:步骤 1、2;阶段一②(两档已归并 Service,PATCH 有落点)。
|
||||
- 风险:激活一致性是本阶段最重的风险(§3.6);Service PATCH 与 Nacos publish 跨系统,须幂等 + 判未生效可重试。
|
||||
|
||||
**步骤 4 · NacosHotConfig 接进 genconfig**
|
||||
- 交付:genconfig 的读取后端提升到 Nacos——优先 NacosHotConfig、回落本地 `generation.yaml`、回落内置默认;NacosHotConfig 作进程级单例接进 worker 启动。middleware 调用面不改。落地阶段〇 D2 建好未接线的 `nacos_hotconfig.py`。
|
||||
- 验证:改 Nacos 生效 dataId → worker 数秒内经 genconfig 读到新预算/阈值(不重启);Nacos 不可达时回落本地 YAML 与默认、生成不受影响;cheap 与 tier2 两档的软预算目标、门阈值都吃上热读。
|
||||
- 依赖:阶段〇 Nacos + NacosHotConfig(已建);阶段一①(middleware 经 genconfig 读预算/阈值)。
|
||||
- 风险:genconfig 现有缓存与 NacosHotConfig 的推送时序要理顺(别让本地 YAML 缓存盖住 Nacos 热值);回落链的优先级要测到位。
|
||||
**步骤 4 · NacosHotConfig 接进 genconfig**(依赖上方 namespace 口径统一前置)
|
||||
- 交付:genconfig 的读取后端提升到 Nacos,落地阶段〇 D2 建好未接线的 `nacos_hotconfig.py`,拆两件。(1) 新增 worker 启动期的 **HotConfig 单例工厂**:`nacos_hotconfig.py` 明确只消费已建好的 v1 `NacosClient`、不自建 client,所以工厂负责把 client 构造齐——server 地址、鉴权(账号密码)、`NO_PROXY`(内网直连绕系统代理,阶段〇同款坑)、真实 `namespaceId`、`group`、按档隔离的 `dataId`,再注入进 NacosHotConfig 并接进 genconfig。(2) genconfig.get 的取值链前端接热源:优先查 NacosHotConfig,再依次回落 env、本地 `generation.yaml`、内置默认(优先级见 §3.4)。middleware 调用面一行不改。
|
||||
- 验证:改 Nacos 生效 dataId → worker 数秒内经 genconfig 读到新预算/阈值(不重启);单测覆盖四条异常/回落路径——**未 start**(工厂没起 NacosHotConfig → genconfig 回落 env/YAML/默认)、**Nacos 不可达**(NacosHotConfig 磁盘快照兜底,再回落本地)、**namespace 配错**(写读不同空间时读不到,佐证前置任务的必要)、**YAML 回落**(热源无值时取本地 YAML 与默认);cheap 与 tier2 两档各读各的 dataId、软预算目标与门阈值都吃上热读。
|
||||
- 依赖:阶段〇 Nacos + NacosHotConfig(已建);阶段一①(middleware 经 genconfig 读预算/阈值);namespace 口径统一前置。
|
||||
- 风险:genconfig 现有缓存与 NacosHotConfig 的推送时序要理顺(别让本地 YAML 缓存盖住 Nacos 热值);回落链优先级(Nacos > env > YAML > 默认)要测到位。
|
||||
|
||||
**步骤 5 · 失败兜底 + 漂移对账**
|
||||
- 交付:激活失败整批判未生效 + 保留上一激活版 + 可重试;Service 不可达兜底;配置漂移对账(拉 Service/worker 投影比对当前激活版)+ 一键重推。
|
||||
@ -229,10 +242,10 @@ flowchart LR
|
||||
|
||||
## 6 风险与回滚
|
||||
|
||||
- **激活一致性(本阶段最重)**:一批 PATCH+publish 跨系统非原子。缓解 = 幂等 + 失败即整批判未生效可重试 + 当前激活版指针只在整批成功后前移 + 保留上一激活版为权威;并发撕裂 MVP 由静默期规避,机制级原子(epoch 戳)留放量后。回滚 = 配置中心永远能重放上一激活版。
|
||||
- **激活一致性(本阶段最重)**:一批 PATCH+publish 跨系统非原子、投影写即被读。缓解 = 值域 sanity 校验前置 + 幂等 + 任一步失败即整批判未生效并立即补偿重推已成功路回上一激活版 + 当前激活版指针只在整批成功后前移 + 保留上一激活版为账本权威(投影层撕裂由即时补偿收敛,不靠"绝不半生效"这种投影层做不到的强承诺);并发撕裂 MVP 由静默期规避,机制级原子(epoch 戳)留放量后。MySQL 指针写失败而投影已成功时,以 `ACTIVATING` 持久态 + 幂等恢复对齐(§3.6)。回滚 = 配置中心永远能重放上一激活版。
|
||||
- **Service 不可达 / Redis 未持久化丢配置**:激活判失败保留旧版;Service 恢复后由漂移对账检出并一键重推。Service Redis 的持久化策略需与运维确认(丢配置是否需 Service 启动即从配置中心拉激活版自愈,可作后续增强)。
|
||||
- **NacosHotConfig 接线破坏 middleware 读参**:回落链(Nacos → 本地 YAML → 内置默认)是保命绳,先在两档单测里锁死三级回落再上;真接线灰度——先只把一个低风险旋钮(如门阈值)切到 Nacos 热读、验稳再推预算目标。回退 = genconfig 后端切回纯本地 YAML(改一处开关)。
|
||||
- **命名空间错配**:默认空间是空串非 "public";写读两侧 namespaceId 一次性核对钉死,否则配置静默推不到(阶段〇同款坑)。
|
||||
- **NacosHotConfig 接线破坏 middleware 读参**:回落链(Nacos → env → 本地 YAML → 内置默认,优先级见 §3.4)是保命绳,先在两档单测里锁死整条回落链再上;真接线灰度——先只把一个低风险旋钮(如门阈值)切到 Nacos 热读、验稳再推预算目标。回退 = genconfig 后端切回纯本地 YAML(改一处开关)。
|
||||
- **命名空间错配**:默认空间是空串非 "public";现状代码的 `public` 字面量偏差作前置任务先修(§3.4 / §4 前置),写读两侧 namespaceId 一次性核对对齐,否则配置静默推不到(阶段〇同款坑)。
|
||||
- **配置集字段映射漂移**:配置集到 `/agent`+`/session` 字段的映射依赖 AgentScope schema,框架升版可能变;映射以 `/agent/schema` 为准、加一致性校验,别硬编码字段名。
|
||||
- **SoT 收口**:本阶段落地后,须把 SoT 里 GitOps/Langfuse 式的旧口径收敛为 yudao 配置中心版本化(账本落 MySQL 版本行)——§5.2 管理面配置管理、§5.8 配置三类的"受治理发版"、ADR-4 配置热取、A13 配置注册表四处,与上级设计 §6 pending 是同一收口面,收口时一并回写,避免两份自称权威触 canonical 门;对上级设计本身的口径回调逐条挂账在 §7,由编排层另单收口、本档不动上级档。
|
||||
|
||||
@ -245,7 +258,8 @@ flowchart LR
|
||||
| 1 | 上级设计 §0 / §3.3 / §3.7"互补"行 | "Nacos 管版本化存储与下发(版本历史/回滚/diff/灰度/推送),取代自建 Flyway 版本表 + 薄读接口" | 版本账本落 yudao MySQL 版本行(prompt 100KB 上限 + 定版原子性所迫,§3.1);Nacos 收窄为路 B 生效下发;"消灭薄读接口"结论不变(NacosHotConfig 仍替它);"灰度发布"收窄为路 B 生效 dataId 层能力、MVP 不启用 |
|
||||
| 2 | 上级设计 §4 阶段二节(交付/验证/风险) | "激活时把 active 版写进 Nacos 并 PATCH""Nacos 承版本/回滚/灰度/推送(取代自建 Flyway 版本表 + 薄读接口)" | 交付 = yudao 治理子域(版本行 + 状态机 + 激活编排)+ 双路激活 + NacosHotConfig 接 genconfig;验证/风险按本档 §4/§6 |
|
||||
| 3 | 上级设计 §3.6 mermaid(UI→yudao→NACOS 写版本→激活 PATCH) | 版本写进 Nacos、激活自 Nacos 侧发出 | yudao(MySQL 账本)→ 激活编排双路下发(PATCH `/agent`+`/session` · publish 生效 dataId);图随文改 |
|
||||
| 4 | SoT 回写口径(架构图说 §5.2 / §5.8 / ADR-4 / A13;上级 §6 已挂"GitOps 口径"收口项) | GitOps / Langfuse 式热取叙述 | "配置中心版本化"的落点 = yudao MySQL 版本行 + 双路激活(本档 frontmatter sot-impact 申报);与上级挂的收口单合并执行 |
|
||||
| 4 | 上级设计 §3.3(middleware 用 nacos-sdk-python `add_listener` 订阅)/ §3.7 生产图(Python middleware 直读预算/阈值)/ §4 阶段〇(middleware 接 nacos-sdk-python listener 读预算/阈值) | middleware 经 nacos-sdk-python `add_listener` 直读 Nacos | middleware 经既有 genconfig 门面读、NacosHotConfig(v1 `add_config_watcher` 长轮询推送)作 genconfig 热源(§3.4);middleware 调用面不变,底层由"直读 Nacos"改为"genconfig 门面 + 热源"。上级核心结论(middleware 从 Nacos 热读预算/阈值、fail-safe 靠 SDK 快照兜底)不变,回调的是实现路径口径;此偏差实由阶段〇引入、阶段二继承 |
|
||||
| 5 | SoT 回写口径(架构图说 §5.2 / §5.8 / ADR-4 / A13;上级 §6 已挂"GitOps 口径"收口项) | GitOps / Langfuse 式热取叙述 | "配置中心版本化"的落点 = yudao MySQL 版本行 + 双路激活(本档 frontmatter sot-impact 申报);与上级挂的收口单合并执行 |
|
||||
|
||||
## 附 图清单与状态
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
| [2026-06-30-配置控制面一次性按序实现-设计](2026-06-30-配置控制面一次性按序实现-设计.md) | 配置控制面(Nacos/RocketMQ/Sentinel 生产基建 + AgentScope 热配) | 阶段〇+一①+一② 已落地(一② SDD 收口 `526e9b3d`);阶段二设计已成稿在评审(下行) |
|
||||
| [2026-06-29-便宜档降AI参与-减摩擦与扩模板覆盖-设计](2026-06-29-便宜档降AI参与-减摩擦与扩模板覆盖-设计.md) | 便宜档减摩擦/扩模板 | 主体已交付(减摩擦+丰富两步+M1 达标);§7 品类扩产已解锁(决策包⑦ 2026-07-02,rubric v2 前置已落 `ba82e63c`),P11×4 批产在编排 |
|
||||
| [2026-07-02-文档治理-SoT注册表与治理门-设计](2026-07-02-文档治理-SoT注册表与治理门-设计.md) | 文档治理(本轮) | 执行中;依据见同日 [普查裁决报告](2026-07-02-文档治理-全量普查与裁决-report.md) |
|
||||
| [2026-07-02-配置控制面阶段二-yudao配置中心-设计](2026-07-02-配置控制面阶段二-yudao配置中心-设计.md) | 配置中心版本源 = yudao MySQL 版本行(prompt MEDIUMTEXT 出 Nacos;Nacos 承路 B 小参下发) | 创始人已拍 B 并收稿;Codex+Opus 双评审中(Codex 已回=需回炉,待 Opus 合并修订) |
|
||||
| [2026-07-02-配置控制面阶段二-yudao配置中心-设计](2026-07-02-配置控制面阶段二-yudao配置中心-设计.md) | 配置中心版本源 = yudao MySQL 版本行(prompt MEDIUMTEXT 出 Nacos;Nacos 承路 B 小参下发) | ✅ 双评审已回并 11 条全修收口(2026-07-02:激活降账本语义+失败即时补偿/namespace 前置/值域校验/dataId 按档隔离/hash 引证改真);待实施排期 |
|
||||
| [2026-07-02-M4广告SDK预接线-设计](2026-07-02-M4广告SDK预接线-设计.md) | M4 广告预接线:三层开关 / 回调验签 fail-closed / 不估算入账(联盟账单为唯一入账源) | 双评审回炉已修(验签加固代码在分支 r3-ad-hardening 待 merge);剩 SVG 门面图 |
|
||||
|
||||
## 在飞计划(docs/plans)
|
||||
|
||||
@ -28,7 +28,7 @@ canonical: true
|
||||
|
||||
- [ ] **W-S1 · 切片一 M3 收尾(生成线头号)** → 工单 = [`M3 cutover plan`](../plans/2026-06-30-便宜档M3-生产cutover-plan.md) S0–S6(已批准,六要素在各步)。解锁 = 决策包③(执行授权 + 窗口;S1 worker 版本口径与配置控制面阶段一② 协同,见该 plan 状态注)。产出喂 S6 放行决策(决策包⑤)。**2026-07-02 状态:决策③ = NO-GO hold**——同根性判定坐实 Service 壳流式聚合缺陷(我方 regression:崩 M3 并行 tool call、斩断续修 = 系统性菜单空壳);fix400 工单在飞(禁并行 call + 聚合补丁 + 2 局 e2e 含续修轮),全绿后再报窗口。
|
||||
- [ ] **W-S2 · 切片二 follow-up** → 工单 = [`n=5 runbook`](../plans/2026-06-28-002-feat-tier2-n5收敛环-go-no-go-plan.md)「后续工单」节:**F-1 ✅ 完成并 merge(2026-07-02 `a3bc8365`:富三门反馈补厚——经济门三数+结构性错配直指;自修实证 2/2、金标 9/9+3/3 ACCEPT、70 单测绿)** → 下一步 F-2 干净复跑(解锁 = 决策包② 窗口,待创始人排);F-3 待网关补强档;F-4 已裁定入质量 canonical §8。
|
||||
- [ ] **W-CFG · 配置控制面** → 阶段一② SDD ✅ 已收口(2026-07-02 `526e9b3d`,决策包① 已拍消费);**阶段二(yudao⊕Nacos 配置中心)设计已成稿并拍 B**(版本账本整体落 yudao MySQL、prompt MEDIUMTEXT 出 Nacos、Nacos 承路 B 小参;基线 `d4471b02`),双评审已回(Codex 需回炉 / Opus 修订后可发布)、修订单在飞;follow-up(真门窗口验证等)见 plan 尾注。
|
||||
- [ ] **W-CFG · 配置控制面** → 阶段一② SDD ✅ 已收口(2026-07-02 `526e9b3d`,决策包① 已拍消费);**阶段二(yudao⊕Nacos 配置中心)设计已成稿并拍 B**(版本账本整体落 yudao MySQL、prompt MEDIUMTEXT 出 Nacos、Nacos 承路 B 小参;基线 `d4471b02`),双评审已回并 11 条全修收口(2026-07-02);**阶段二设计定稿、待实施排期**;follow-up(真门窗口验证等)见 plan 尾注。
|
||||
- [ ] **W-A11 · 切片三收尾** → 受计费真后端 e2e(解锁 = 决策包④ 窗口;plan = `git show 8ea97234:docs/plans/2026-06-28-003-feat-studio-A11-对话式调整回路-plan.md`,M1–M5 已完成、只余此项)。
|
||||
- [ ] **W-REAL · 16 周真实化批次**(**R1/R2/R3/R4/R6 ✅ 2026-07-02 全部完成并 merge**;剩 R5 受 feed 内容解锁):
|
||||
- ✅ **R1 telemetry MQ 异步聚合**(`f2d85a07`)——`/events/batch`·`/perf/beacon` 改投 RocketMQ 异步消费(灰度开关 `telemetry.mq.enabled` 默认关 = 现行行为逐字不变);59 单测绿 + mini-infra 真 broker 往返 IT 绿;`consumeThreadNumber=consumeThreadMax=8` 破死参数坑。
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user