merge: W-REAL R4 评审遗留 16+1 条对账清欠(G1 扩代码扫描面+负向测试/品牌漏网/ad-slot 契约补 callback/总账对账表)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
lili 2026-07-02 20:07:17 -07:00
commit eba757580d
5 changed files with 72 additions and 19 deletions

View File

@ -22,6 +22,17 @@ import sys
# 退役品牌根的唯一字面量(活层散文一律用「退役品牌名」间接表述,勿再写出字面量)
BRAND_RETIRED = "造梦"
# G1 品牌不变量的代码扫描面(W-REAL R4 补:防品牌回流到模块根 package.json / index.html 与 wg1/ 等代码——
# 评审曾指出门只扫活层 md 会放过玩家/管理台可见的代码字面量)。业务代码目录 + 相关源码后缀;
# .agents 不入(门自身源码持有 BRAND_RETIRED 字面量,扫它会自噬)、docs 由 walk_md 覆盖。
BRAND_CODE_BASES = ["game-runtime", "game-studio", "game-admin", "wg1", "tier2",
"cheap-worker", "game-cloud", "contracts", "deploy", "spikes"]
BRAND_CODE_EXTS = (".json", ".html", ".ts", ".js", ".mjs", ".cjs", ".vue",
".py", ".java", ".yaml", ".yml")
# 依赖/构建产物/归档目录原地裁剪(既防误报也快)。
BRAND_PRUNE_DIRS = {"node_modules", "target", "dist", "build", ".git",
"_archive", "_recall", ".venv", "__pycache__"}
ROOT = os.path.abspath(sys.argv[1]) if len(sys.argv) > 1 else os.path.abspath(
os.path.join(os.path.dirname(__file__), "..", ".."))
@ -56,6 +67,21 @@ def walk_md(bases, exclude_archives=True):
return out
def walk_code(bases, exts):
"""遍历业务代码目录里指定后缀的源文件(供 G1 品牌扫描面防回流用;prune 掉依赖/构建/归档目录)。"""
out = []
for base in bases:
top = os.path.join(ROOT, base)
if not os.path.isdir(top):
continue
for dp, dns, fs in os.walk(top):
dns[:] = [d for d in dns if d not in BRAND_PRUNE_DIRS] # 原地裁剪不进依赖/构建目录
for fn in fs:
if fn.endswith(exts): # str.endswith 接受后缀元组
out.append(os.path.join(dp, fn))
return out
def read(fp):
try:
with open(fp, encoding="utf-8", errors="ignore") as f:
@ -92,13 +118,19 @@ def check(name, problems):
# ---------- G1 品牌不变量 ----------
def g1():
problems = []
# ① 活层策展 md(AGENTS.md / docs / .agents):日期留痕档豁免。
for fp in walk_md(["AGENTS.md", "docs", ".agents"]):
if DATED.match(os.path.basename(fp)):
continue
for i, line in enumerate(read(fp).splitlines(), 1):
if BRAND_RETIRED in line and "brand-ok" not in line:
problems.append(f"{rel(fp)}:{i} {line.strip()[:60]}")
check("G1 品牌不变量(活层无退役品牌根)", problems)
# ② 业务代码目录源文件(W-REAL R4 补扫描面):模块根 package.json / index.html 与 wg1/ 等代码防品牌回流。
for fp in walk_code(BRAND_CODE_BASES, BRAND_CODE_EXTS):
for i, line in enumerate(read(fp).splitlines(), 1):
if BRAND_RETIRED in line and "brand-ok" not in line:
problems.append(f"{rel(fp)}:{i} {line.strip()[:60]}")
check("G1 品牌不变量(活层 md + 业务代码无退役品牌根)", problems)
# ---------- G2 canonical 唯一性 + 注册表对账 ----------

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
# 文档治理门薄壳:调用 docs-gate.py(六检)。用法:bash .agents/tools/docs-gate.sh
# 文档治理门薄壳:调用 docs-gate.py(七检 G1-G7)。用法:bash .agents/tools/docs-gate.sh
# 退出码 0=全绿;非零=失败检数。pre-commit 与 wave-close 第 8 步必跑。
set -uo pipefail
exec python3 "$(cd "$(dirname "$0")" && pwd)/docs-gate.py" "$(cd "$(dirname "$0")/../.." && pwd)"

View File

@ -18,9 +18,9 @@
"enum": ["rewarded", "interstitial", "banner"]
},
"provider": {
"description": "广告联盟csj=穿山甲 / gdt=优量汇 / mock=桩MVP 默认)",
"description": "广告联盟csj=穿山甲 / gdt=优量汇 / mock=桩MVP 默认)/ callback=sandbox 自回调桩M4 服务端回调验签演进,签名校验走桩直通;见 api-schemas/ad.yaml /app-api/ad/reward/callback 与 ad 模块 CallbackAdProvider",
"type": "string",
"enum": ["csj", "gdt", "mock"]
"enum": ["csj", "gdt", "mock", "callback"]
},
"placement": {
"description": "触发场景game_end=本局结束 / pause=暂停 / feed=游戏流间隙",

View File

@ -120,24 +120,45 @@ canonical: true
四模块game-runtime / game-studio / tier2 / wg1并行评审得 25 条真发现、0 个 P0下列 9 条 P1品牌两条合并呈现+ 7 条 P2 未闭。真正带真金白银风险的是 wg1、tier2 两条生成线的成本与幂等闸尚未焊死,应在 W-G1 切默认产线、tier2 批量开闸之前处理。
> **W-REAL R4 清欠对账2026-07-02逐条读当前代码坐实、不凭文档推断**16 条 = 7 moot、6 已修、1 存活待修、2 本次修(品牌门扫描面);另协调者追加第 17 条ad-slot 契约漂移)本次修。下方原始发现明细勾选态已按本表更新(存活项保留未勾)。
>
> | 条目 | 判定 | 依据(读码坐实) |
> |---|---|---|
> | P1① wg1 `/generate` 幂等 | moot | wg1 是退役 spike无生产 Java 接线,仅 game-cloud 测试/注释引用);生产便宜档 = cheap-worker幂等走后端 WorkerDispatchClient + idempotencyKey |
> | P1② wg1 max_tokens 未透传 | moot | 同上退役cheap-worker 已透传(`_bootstrap.build_cheap_model` / `cheap_service_driver``parameters.max_tokens` |
> | P1③ tier2 ¥ 硬闸跨 resume 不累计 | 已修 | 架构改单 POST 内联续修,`CircuitBreakerMiddleware` 会话级实例 `on_model_call` 累加 `spent_rmb` 调用前 fail-closed`soft_budget` 演进(配置控制面阶段一①);`test_budget_soft_stop` 覆盖 |
> | P1④ wg1 契约真空 | 已修 | `contracts/agent-loop/{verdict,tier2-source-project,tier2-verdict}.schema.json` + `trace/tier2-trace-event.schema.json` 已建v1 clicker 世代已换 |
> | P1⑤ tier2 服务态主链未真跑 | 已修(核心) | 扁平探测零产出孤儿已由 `tool_groups[*].tools` 抽取修复app.py:120「2026-06-24 实证修复」)+ B1 真驱暴露;端到端批量清单在 `tier2/.agent`(仍待 mini-desktop属正常 spike→prod |
> | P1⑥ game-studio CSP 注释失真 | 已修 | `inject.ts` CSP 已移除 `unsafe-eval`(注释据实述「不含 eval/new Function 故不需」),无 `scanLogic`/`gamedef` 失实表述 |
> | P1⑦ game-studio vue-i18n 卡类型门 | 已修 | `package-lock.json` 已含 `vue-i18n@10.0.8``vue-tsc@3.3.4`(合 ^3.2.8/ `typescript@6.0.3`(合 ~6.0.2)对齐,评审「实装 6.0.3」错配已消(本机未 install 不影响权威机 `npm ci` |
> | P1⑧ 品牌残留 + 机器门扫描面(合并 GR-01+WG1-04 两条 P1 | **本次修** | 三处品牌早修b31cc37aG1 仅扫 .md 有洞 → 本次扩 `walk_code` 覆盖业务代码目录(负向测试证拦回流)+ 清漏网 `game-admin` 一处退役品牌菜单标题 → `绘境运营` |
> | P2① game-runtime v1→v2 标注漂移 | moot | `build-from-source.mjs` / `gd-runtime.js` 已删gamedef v1 世界全删src/host 只剩 3 层架构 `boot-game-host` / `generic-host-config` |
> | P2② tier2 `validate_play_scene` 子串校验 | 已修 | 切片二 U4 加 `_strip_js_comments_strings`,剥注释+字符串后判评审短期诉求AST 结构判定记为中期 followup |
> | P2③ tier2 screenshot docstring 冲突 | moot | tier2 代码已无 canvas 像素回读(`getImageData`/`readback`/`toDataURL` 全空screenshot 只读落盘 PNGdocstring「零截图参与」现属实 |
> | P2④ tier2 bootstrap 鉴权头口子 | **存活待修** | `_post``X-User-Id` 口子 + 无重试退避仍在bootstrap.py:99卡点 = 需真实 `deps.py` 鉴权契约(部署 smoke 接缝),非本机最小改动可完成,列部署窗口 followup |
> | P2⑤ wg1 callback 孤儿 | moot | wg1 退役;`cheap-worker/worker_service.py` 用 job 携带的 per-job callback URLHMAC 回调) |
> | P2⑥ wg1 `_judge_vision` 绕过重试 | moot | wg1 退役 spike不在生产路径 |
> | P2⑦ wg1 基建 subprocess 无 check | moot | wg1 退役 spike不在生产路径 |
> | R4-17 ad-slot provider 枚举漂移(协调者追加) | **本次修(跨端契约)** | `ad-slot.schema.json` enum 缺 `callback`,而 `ad.yaml``CallbackAdProvider`(真实现 `PROVIDER="callback"`已支持additive 加 `callback` + 对齐描述DB VARCHAR 注释 / DO Javadoc 仍列 csj/gdt/mockdoc-only、SQL 为 Flyway 版本档不改)——留终审 |
**P19 条)**
- [ ] **wg1 `/generate` 无幂等去重**`wg1/gen-worker/worker/service.py:378`):仅 `threading.Lock` 串行化,同一 traceId 重投会重复真烧便宜模型 + 重复 HMAC 回调,后端可能重复建版本/组包。切默认产线前必修(内存 set 起步,崩溃恢复用 results/ jsonl
- [ ] **wg1 `run_studio` 的 `max_tokens` 未透传**`wg1/gen-worker/worker/agent_loop/studio.py:231`形参声明了却没接到底层调用复杂局便宜模型输出被默认上限截断→取不到完整代码块→parse 失败重试,把 token 白烧在无谓重试上,直接拖累「成功率冲 80%」。
- [ ] **tier2 ¥ 成本硬闸跨 resume 不累计**`tier2/gen-worker/service/app.py:192`):熔断中间件每个 chat 回合重建、计数从 0 起,`rmb_hard_limit=3.0` 在默认 6 回合 resume 下形同虚设,单款实际可烧约 7 倍单回合上限而硬闸永不触发。批量开闸前必修(把 spent_rmb 提到 session 维度跨回合累计)。
- [ ] **wg1 契约真空**`wg1/gen-worker/worker/service.py:91`worker 产的 engineBundle / 九门 verdict / 9 维 trace 无任何 `contracts/` schema 背书,评审锚点的 verdict/game-design schema 还停在 v1 clicker 世代字段世代不符worker↔后端 trace 子集口径只散在注释里,键名漂移无门可拦。补新 schema或在设计文档显式声明 engine 路不消费 v1 契约并指向新 schema。
- [ ] **tier2 服务态主链未端到端真跑**`tier2/gen-worker/service/app.py:105`BackendStore 落库 / MCP / L2·L3 / 富游戏三门只有 schema 形状、缺真跑证据代码里留着「扁平探测全空→服务态生成零产出」的实证注释属孤儿风险。0 号 spike 真驱后把端到端验证列成显式验收清单挂进 `tier2/.agent`,每兑现一项去掉「待 spike」表述并附证据路径。
- [ ] **game-studio host CSP 注释失真**`game-studio/src/host/inject.ts:69`iframe CSP 授了 `unsafe-eval`,注释援引本模块根本不存在的 `gamedef` / `scanLogic` 运行时当作既成安全保障(违反「不得把未验证声明当事实」),且多授了当前代码不需要的 eval 能力。删掉不存在的 `scanLogic` 表述据实改述真实边界;若引擎 bundle 不需 eval 则从 CSP 移除 `unsafe-eval`
- [ ] **game-studio `vue-i18n` 缺失卡类型门**`game-studio/package.json`):声明 `^10.0.0` 却没装26 条 TS2307 卡死 `vue-tsc` 与 CI`vue-tsc` 声明 `^3.2.8` 与实装 `6.0.3``typescript ~6.0.2` 不在同一兼容线,`npm ci` 不可预期。在权威构建机装包 + 对齐版本声明 + 提交 lockfile合入前清掉。
- [ ] **品牌红线残留 + 机器门扫描面有洞**(合并 GR-01 + WG1-04 两条 P1 + §四 index.html 补正活层三处退役旧名「造梦AI」——`game-runtime/package.json:6``game-studio/index.html:7`(玩家浏览器标签页可见,最显眼)、`wg1/gen-worker/worker/service.py:34`;更要紧的是品牌不变量门只扫 `src/` 会放过模块根 `package.json` / `index.html``wg1/` 目录。改三处字符串之外,须把门的扫描面扩到各模块根与 wg1/ 防回流。 <!-- brand-ok:门证据行,引用旧名字面量属必要 -->
- [x] **wg1 `/generate` 无幂等去重**`wg1/gen-worker/worker/service.py:378`):仅 `threading.Lock` 串行化,同一 traceId 重投会重复真烧便宜模型 + 重复 HMAC 回调,后端可能重复建版本/组包。切默认产线前必修(内存 set 起步,崩溃恢复用 results/ jsonl
- [x] **wg1 `run_studio` 的 `max_tokens` 未透传**`wg1/gen-worker/worker/agent_loop/studio.py:231`形参声明了却没接到底层调用复杂局便宜模型输出被默认上限截断→取不到完整代码块→parse 失败重试,把 token 白烧在无谓重试上,直接拖累「成功率冲 80%」。
- [x] **tier2 ¥ 成本硬闸跨 resume 不累计**`tier2/gen-worker/service/app.py:192`):熔断中间件每个 chat 回合重建、计数从 0 起,`rmb_hard_limit=3.0` 在默认 6 回合 resume 下形同虚设,单款实际可烧约 7 倍单回合上限而硬闸永不触发。批量开闸前必修(把 spent_rmb 提到 session 维度跨回合累计)。
- [x] **wg1 契约真空**`wg1/gen-worker/worker/service.py:91`worker 产的 engineBundle / 九门 verdict / 9 维 trace 无任何 `contracts/` schema 背书,评审锚点的 verdict/game-design schema 还停在 v1 clicker 世代字段世代不符worker↔后端 trace 子集口径只散在注释里,键名漂移无门可拦。补新 schema或在设计文档显式声明 engine 路不消费 v1 契约并指向新 schema。
- [x] **tier2 服务态主链未端到端真跑**`tier2/gen-worker/service/app.py:105`BackendStore 落库 / MCP / L2·L3 / 富游戏三门只有 schema 形状、缺真跑证据代码里留着「扁平探测全空→服务态生成零产出」的实证注释属孤儿风险。0 号 spike 真驱后把端到端验证列成显式验收清单挂进 `tier2/.agent`,每兑现一项去掉「待 spike」表述并附证据路径。
- [x] **game-studio host CSP 注释失真**`game-studio/src/host/inject.ts:69`iframe CSP 授了 `unsafe-eval`,注释援引本模块根本不存在的 `gamedef` / `scanLogic` 运行时当作既成安全保障(违反「不得把未验证声明当事实」),且多授了当前代码不需要的 eval 能力。删掉不存在的 `scanLogic` 表述据实改述真实边界;若引擎 bundle 不需 eval 则从 CSP 移除 `unsafe-eval`
- [x] **game-studio `vue-i18n` 缺失卡类型门**`game-studio/package.json`):声明 `^10.0.0` 却没装26 条 TS2307 卡死 `vue-tsc` 与 CI`vue-tsc` 声明 `^3.2.8` 与实装 `6.0.3``typescript ~6.0.2` 不在同一兼容线,`npm ci` 不可预期。在权威构建机装包 + 对齐版本声明 + 提交 lockfile合入前清掉。
- [x] **品牌红线残留 + 机器门扫描面有洞**(合并 GR-01 + WG1-04 两条 P1 + §四 index.html 补正活层三处退役旧名「造梦AI」——`game-runtime/package.json:6``game-studio/index.html:7`(玩家浏览器标签页可见,最显眼)、`wg1/gen-worker/worker/service.py:34`;更要紧的是品牌不变量门只扫 `src/` 会放过模块根 `package.json` / `index.html``wg1/` 目录。改三处字符串之外,须把门的扫描面扩到各模块根与 wg1/ 防回流。 <!-- brand-ok:门证据行,引用旧名字面量属必要 -->
**P27 条)**
- [ ] **game-runtime v1→v2 契约标注漂移**`game-runtime/src/host/build-from-source.mjs``gd-runtime.js` 文件头,评审 GR-02source-project 契约已升级为 `oneOf(v1|v2)`、v1 标注冻结只读、v2 多文件 `src/` 定为终态,但活实现仍整建在 v1 上且无标注指向该判别式,维护者易把冻结的 v1 当终态继续加码。文件头各补一行演进状态注释、链到 schema 判别式(只加注释不改逻辑)。
- [ ] **tier2 `validate_play_scene` 文本子串校验平台命脉接线**`tier2/gen-worker/worker/run.py:401`):裸子串/正则启发式决定是否拦 build 并回喂自纠指引agent 把 `bindInput`/`tick` 写进注释即假绿、用别名/换行即假红误导自纠。中期改 AST 结构判定,短期至少剥注释/字符串后再扫。
- [ ] **tier2 screenshot docstring 与像素回读数据流冲突**`tier2/gen-worker/worker/toolkit.py:262`docstring 写「L1/L2 判定零截图参与」,实际 harness 在回读 canvas 像素产 advisory 观测(严格不进 decision。纪律没破、纯措辞误导契约消费方据实校准零成本
- [x] **game-runtime v1→v2 契约标注漂移**`game-runtime/src/host/build-from-source.mjs``gd-runtime.js` 文件头,评审 GR-02source-project 契约已升级为 `oneOf(v1|v2)`、v1 标注冻结只读、v2 多文件 `src/` 定为终态,但活实现仍整建在 v1 上且无标注指向该判别式,维护者易把冻结的 v1 当终态继续加码。文件头各补一行演进状态注释、链到 schema 判别式(只加注释不改逻辑)。
- [x] **tier2 `validate_play_scene` 文本子串校验平台命脉接线**`tier2/gen-worker/worker/run.py:401`):裸子串/正则启发式决定是否拦 build 并回喂自纠指引agent 把 `bindInput`/`tick` 写进注释即假绿、用别名/换行即假红误导自纠。中期改 AST 结构判定,短期至少剥注释/字符串后再扫。
- [x] **tier2 screenshot docstring 与像素回读数据流冲突**`tier2/gen-worker/worker/toolkit.py:262`docstring 写「L1/L2 判定零截图参与」,实际 harness 在回读 canvas 像素产 advisory 观测(严格不进 decision。纪律没破、纯措辞误导契约消费方据实校准零成本
- [ ] **tier2 bootstrap 鉴权头占位口子**`tier2/gen-worker/service/bootstrap.py:99`REST 客户端 `X-User-Id` 留口子待对齐,四步串行启动无重试/幂等new-api 偶发 502 会让启动失败或重复注册凭据。smoke 时按真实 `deps.py` 定死鉴权头 + 加幂等与有限重试退避。
- [ ] **wg1 回调 `callback` 孤儿字段**`wg1/gen-worker/worker/service.py:8`):文件头文档声明 job 携带 `callback`,但全程只用进程级 `state.callback_url``job.get("callback")` 从不读取;执行器若按文档传 per-job 回调会被无声丢弃。删文档声明,或真接线 + 地址白名单防 SSRF。
- [ ] **wg1 `_judge_vision` 绕过重试封装**`wg1/gen-worker/worker/agent_loop/studio.py:190`):视觉位直接调 `client.chat.completions.create`,绕过 `_client.chat` 的 tries=3 突发重试(仍有 SDK 级 max_retries=2遇网关瞬时 502 更易被吞成 panel error、顾问位无声失效。给 `_client` 加多模态 chat 变体复用重试。
- [ ] **wg1 基建类 subprocess 无 check**`wg1/gen-worker/worker/validate.py:86``run.py:48/62`build/play 子进程因环境问题node 缺失、脚本路径错)非零退出被当普通失败回喂模型重试,掩盖基建故障、白烧重试 token 才暴露。对基建类区分 returncode如 127快速失败标 infra_fail、不进回喂循环。
- [x] **wg1 回调 `callback` 孤儿字段**`wg1/gen-worker/worker/service.py:8`):文件头文档声明 job 携带 `callback`,但全程只用进程级 `state.callback_url``job.get("callback")` 从不读取;执行器若按文档传 per-job 回调会被无声丢弃。删文档声明,或真接线 + 地址白名单防 SSRF。
- [x] **wg1 `_judge_vision` 绕过重试封装**`wg1/gen-worker/worker/agent_loop/studio.py:190`):视觉位直接调 `client.chat.completions.create`,绕过 `_client.chat` 的 tries=3 突发重试(仍有 SDK 级 max_retries=2遇网关瞬时 502 更易被吞成 panel error、顾问位无声失效。给 `_client` 加多模态 chat 变体复用重试。
- [x] **wg1 基建类 subprocess 无 check**`wg1/gen-worker/worker/validate.py:86``run.py:48/62`build/play 子进程因环境问题node 缺失、脚本路径错)非零退出被当普通失败回喂模型重试,掩盖基建故障、白烧重试 token 才暴露。对基建类区分 returncode如 127快速失败标 infra_fail、不进回喂循环。
### 联调(把"模块编译通过"转成"可演示闭环"= Doc A P0 可验证的硬通货)
- [x] **`deploy/smoke-test.sh` 五链路冒烟门2026-06-11** — API 级就绪门:只读 12/12 + `--deep` 13/13 全过health/鉴权 + 链路①四模板就绪+draft + 链路②feed非空+zones+project/my + 链路③runtime/package取包 + 链路④ad/钱包/收益 + 链路⑤feed携qualityScore回灌 + deep:generate入队。**5 条链路后端 API 全绿**CORS/鉴权test1 token从前端 origin 验证通过。**实测 gotcha**feed item 的 `packageUrl` 恒 null真实取包走 `GET /app-api/runtime/package/{versionId}`(已写入脚本注释)。

View File

@ -248,7 +248,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
name: 'Wanxiang',
redirect: '/wanxiang/review',
meta: {
title: '造梦运营',
title: '绘境运营',
icon: 'ep:management',
alwaysShow: true
},