- D1: Registry 3 prompt(策划/对抗/fix)+eval 骨架+registry 注册 - D2: agent-loop 2 schema + 4 模板 schema(对齐 gen_spike 真源, additionalProperties:false) - D3: 编排器+裁决引擎(judge D1-D10 决策表/账本幂等重放/预算闸熔断/eval 回流/批报告), 59 单测绿(mini-desktop) - D5: 玩家 CDP 取证 player_cdp.py(真点击/蛇形→驼峰映射/demo 三信号/三角合成判定), 9001 自测 PASS - (D4 后端件已在 9bf3d54 先行入库, 三条 mvn 两轮独立实跑全绿) - spec: 评审版(已拍板)+execution 版(已审定+建设期补充裁决 D4-a~d/D5-a~c/D2-a/D3-a) - W2 试点/种子 9003-9008/B4 四链路烟测 产物与总账/作战清单同步 - eval 种子: C1 spike 52 条转入 config.clicker-designer(inputs 52/labels 13) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
169 lines
10 KiB
JSON
169 lines
10 KiB
JSON
{
|
||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||
"$id": "https://wanxiang.ai/contracts/agent-loop/verdict.schema.json",
|
||
"title": "Verdict",
|
||
"description": "agent 化生成 QA 闭环工件契约②:Verdict 终判记录(HJ-AGENT-LOOP-EXEC-001 §6.2,评审版 HJ-AGENT-LOOP-REVIEW-001 §3.2 原文照落,owner=WS2)。由裁决引擎 judge.py 按 §10 显式决策表纯代码产出(无 LLM;取证纪律=「agent 自述一律不作证据」,playReport 等全部由编排器代码对 CDP 捕获原始数据计算)。落 JSONL 账本终判行(type=\"verdict\",§7.2)并作 eval 回流 labels.jsonl 源(§7.7)。注意:infra_fail(§10 D7)不产 Verdict——不计分母、designId 可重放,仅记账本 stage 行,故 decision 无 infra 取值。",
|
||
"type": "object",
|
||
"required": ["designId", "taskId", "decision", "structureOk", "runnableOk", "playReport", "findings", "reasons", "round", "evidence"],
|
||
"additionalProperties": false,
|
||
"properties": {
|
||
"designId": {
|
||
"description": "对应 GameDesign.designId(sha256(idea+templateId+round) 的 64 位小写 hex),账本幂等重放键。",
|
||
"type": "string",
|
||
"pattern": "^[a-f0-9]{64}$"
|
||
},
|
||
"taskId": {
|
||
"description": "后端生成任务 ID(game_aigc_task.id,BIGINT)。JSON 传输形态兼容数字与字符串(Jackson 对 Long 的序列化策略可能转字符串防 JS 精度丢失),两形态均合法;建议编排器落账本时统一字符串化。文本面 kill(D2/D3/D4/D6)按 §16-1 裁决也回调 failed 落终态,故任务必已存在、本字段必含。",
|
||
"type": ["integer", "string"]
|
||
},
|
||
"versionId": {
|
||
"description": "游戏版本 ID(game_version.id,BIGINT),可选字段(评审版 §3.2 的 versionId?):仅回调三表落包成功后存在;decision=accept 时必含(顶层 allOf 强制)。未到落包即终判的文本面分支无此字段。传输形态同 taskId(数字或字符串均合法)。",
|
||
"type": ["integer", "string"]
|
||
},
|
||
"decision": {
|
||
"description": "终判三值(§10 决策表唯一输出):accept=structureOk∧runnableOk∧无 P0/P1 残留∧查重通过四条 AND 全真,进发布段(金丝雀每批≤10);fix=对抗 P1 findings 回灌策划重出(round→1 全流程重走);kill=schema 两次不过 / 批内撞重 / 对抗 P0 即杀 / P1 残留额度用尽 / 实玩重试后仍不可运行(D9 kill-runnable,任务保持 succeeded)。",
|
||
"type": "string",
|
||
"enum": ["accept", "fix", "kill"]
|
||
},
|
||
"structureOk": {
|
||
"description": "结构层判定(§10 E1 schema 门):config 通过对应模板 schema(contracts/templates/*.schema.json)校验。注意与查重门(E2)并列,本字段不含查重语义。",
|
||
"type": "boolean"
|
||
},
|
||
"runnableOk": {
|
||
"description": "可运行层判定(§9.4 五条 AND,全部以 CDP 捕获原始数据核对):①捕获 game_loaded ②捕获 game_end 且 data.completed===true(布尔严格等值)③durationMs>0(源=线缆蛇形字段 data.duration_ms)④零 game_error 信封且 console 无致命错误 ⑤所玩包 checksum/config 与落包一致(demo 兜底属 infra_fail,不在本判定内)。",
|
||
"type": "boolean"
|
||
},
|
||
"playReport": {
|
||
"description": "玩家 agent 取证报告(§9.6 归一化产物)。可空条件(§6.2 补充细化):null 仅允许出现在未到实玩阶段即终判的分支——schema-kill(D2)/批内撞重-kill(D3)/对抗 P0-kill(D4)/fix(D5)/P1 残留-kill(D6);decision=accept 必为对象(顶层 allOf 强制,五条 AND 的证据载体);kill-runnable(D9)已实玩,应携带报告。内部信号 demoFallback/score 不入本契约,仅入账本 stage 行(§9.6)。",
|
||
"type": ["object", "null"],
|
||
"required": ["loaded", "clicks", "gameEnd", "consoleErrors", "assetLoadErrors", "packageChecksumVerified", "emitsCaptured"],
|
||
"additionalProperties": false,
|
||
"properties": {
|
||
"loaded": {
|
||
"description": "是否捕获 game_loaded 生命周期信封(§9.4 ①)。",
|
||
"type": "boolean"
|
||
},
|
||
"clicks": {
|
||
"description": "实际派发的真实点击次数(CDP Input.dispatchMouseEvent mousePressed/mouseReleased 成对计 1 次,§9.3-5;禁止 evaluate_script 篡改游戏状态)。",
|
||
"type": "integer",
|
||
"minimum": 0
|
||
},
|
||
"gameEnd": {
|
||
"description": "game_end 信封归一化结果;未捕获到 game_end(如等待超时)时为 null。",
|
||
"type": ["object", "null"],
|
||
"required": ["completed", "durationMs"],
|
||
"additionalProperties": false,
|
||
"properties": {
|
||
"completed": {
|
||
"description": "是否通关。v1 clicker runtime 达 target 才发 game_end(game-studio/src/host/runtime/index.ts:167),实测恒 true;false 为预留语义(到点未通关/未来模板失败结束场景),schema 不锁死 const true。runnableOk ② 仅认 completed===true。",
|
||
"type": "boolean"
|
||
},
|
||
"durationMs": {
|
||
"description": "单局时长(毫秒)。源=信封原始蛇形字段 data.duration_ms(线缆格式,runtime/index.ts:167),由编排器显式映射归一为驼峰 durationMs(§9.4 ③ 硬性映射规则,否则五条 AND 的③恒 false)。本字段如实记录捕获值(含 0);「durationMs>0」是 runnableOk 条款而非本字段约束——防 startMs 缺省=0 假象须留原值证据。",
|
||
"type": "integer",
|
||
"minimum": 0
|
||
}
|
||
}
|
||
},
|
||
"consoleErrors": {
|
||
"description": "console error 级条目文本(已排除资源 404/favicon 类网络噪声白名单,§9.4 ④);Runtime.exceptionThrown 异常亦归入。",
|
||
"type": "array",
|
||
"items": { "type": "string" }
|
||
},
|
||
"assetLoadErrors": {
|
||
"description": "telemetry 信封中 asset_load_error 计数(§9.4 ④:>0 仅记录不否决;v1 组包 assets=[] 理论为 0)。",
|
||
"type": "integer",
|
||
"minimum": 0
|
||
},
|
||
"packageChecksumVerified": {
|
||
"description": "浏览器侧核验(§9.5):Network 捕获到 /app-api/runtime/package/{versionId}/manifest 成功响应且响应原文 sha256 == 期望 checksum(=回调组包记账的 sha256(T1))。",
|
||
"type": "boolean"
|
||
},
|
||
"emitsCaptured": {
|
||
"description": "捕获的 wanxiang-game-sdk 信封事件名按时序(如 [\"game_loaded\",\"game_start\",\"game_end\"],含 telemetry 类信封事件名)。",
|
||
"type": "array",
|
||
"items": { "type": "string" }
|
||
}
|
||
}
|
||
},
|
||
"findings": {
|
||
"description": "对抗评审产出(prompt:quality.adversary-review,输出与本数组同构;§5.3-2)。判定口径:P0=违规/敏感/年龄不适(D4 即杀);P1=题文不符、target 与意图矛盾、文案不通或占位感(D5 回炉一次,额度用尽 D6 kill);P2=可改进建议(不参与判定,仅留档)。无问题=空数组。对抗评审不可见任何试玩数据。",
|
||
"type": "array",
|
||
"items": {
|
||
"type": "object",
|
||
"required": ["severity", "issue", "suggestion"],
|
||
"additionalProperties": false,
|
||
"properties": {
|
||
"severity": {
|
||
"description": "严重级:P0=即杀 / P1=可修回炉 / P2=仅留档建议。",
|
||
"type": "string",
|
||
"enum": ["P0", "P1", "P2"]
|
||
},
|
||
"issue": {
|
||
"description": "问题描述(简体中文,非空)。",
|
||
"type": "string",
|
||
"minLength": 1
|
||
},
|
||
"suggestion": {
|
||
"description": "修改建议(简体中文;fix 轮经 fix.design-revise 回灌策划,未指出字段原样保留)。",
|
||
"type": "string"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"reasons": {
|
||
"description": "裁决理由,受控词表(§6.2 补充:取 §10 决策表「reasons 记账值」列,便于批报告聚合)。固定值:schema_retry(D1 本地重出)/schema_invalid_after_retry(D2)/duplicate_in_batch(D3)/p1_fix_round(D5)/p1_residual_after_fix(D6)/runnable_retry(D8)/runnable_fail_after_retry(D9)/accept(D10);前缀模式:p0_<类别>(D4,类别如违规/敏感/年龄不适)、infra_<类别>(D7,类别见 §11:llm/backend/callback/callback_tx/task_poll/package_verify/demo_fallback/batch_timeout)。",
|
||
"type": "array",
|
||
"minItems": 1,
|
||
"items": {
|
||
"anyOf": [
|
||
{
|
||
"type": "string",
|
||
"enum": ["schema_retry", "schema_invalid_after_retry", "duplicate_in_batch", "p1_fix_round", "p1_residual_after_fix", "runnable_retry", "runnable_fail_after_retry", "accept"]
|
||
},
|
||
{
|
||
"type": "string",
|
||
"pattern": "^p0_.+"
|
||
},
|
||
{
|
||
"type": "string",
|
||
"pattern": "^infra_.+"
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"round": {
|
||
"description": "终判时的回炉计数(0=首轮终判,1=回炉轮终判),口径同 GameDesign.round(§10.1 总则:全流程回炉额度合计 1 轮;实玩重试不消耗额度、不改 round)。",
|
||
"type": "integer",
|
||
"enum": [0, 1]
|
||
},
|
||
"evidence": {
|
||
"description": "证据索引:traceId 贯穿后端任务链路;promptVersions 记录本设计走过的各 prompt 版本(eval 回流按其涉及的 prompt id 路由落盘,§7.7)。",
|
||
"type": "object",
|
||
"required": ["traceId", "promptVersions"],
|
||
"additionalProperties": false,
|
||
"properties": {
|
||
"traceId": {
|
||
"description": "后端生成任务 trace_id(game_aigc_task.trace_id,UUID 生成实际唯一;回调对接与 §12.3 冒烟 SQL 的定位键)。",
|
||
"type": "string",
|
||
"minLength": 1
|
||
},
|
||
"promptVersions": {
|
||
"description": "prompt id → 版本号映射(如 {\"config.clicker-designer\":\"1.0.0\",\"quality.adversary-review\":\"1.0.0\"}),值为 registry.yaml 中的 version 字符串。",
|
||
"type": "object",
|
||
"additionalProperties": { "type": "string" }
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"allOf": [
|
||
{
|
||
"if": { "properties": { "decision": { "const": "accept" } }, "required": ["decision"] },
|
||
"then": {
|
||
"required": ["versionId"],
|
||
"properties": { "playReport": { "type": "object" } }
|
||
}
|
||
}
|
||
]
|
||
}
|