games-development-ai/contracts/play-loop/verdict-feedback.schema.json

149 lines
11 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://wanxiang.ai/contracts/play-loop/verdict-feedback.schema.json",
"title": "VerdictFeedback",
"description": "VerdictFeedback 判卷反馈契约(生成引擎 agentic 架构设计代号 C6,2026-07-03 一次性裁决 Δ1)。每次真玩判分没过门时,回喂给续修 agent 的那份结构化反馈:说清哪道门没过、卡在哪个阶段、这局是用哪种驱动器判的、证据在哪、疑似哪段代码坏了、往哪个方向修。它不是终判本身(终判是 tier2-verdict / 便宜档九门 verdict),也不是观测事件(那是 contracts/trace 的 trace 记录,是给台账看的旁路轨迹);它是判分→反馈→续修这条闭环里、专门喂回 agent 让它接着修的那份载荷。为什么要钉成结构:现在这份反馈是被拼成一整段中文字符串产出的(tier2 run.py:1070 verdict_feedback、便宜档 gate_judge.py:109 _cheap_verdict_feedback),而字符串里丢字段是无声的——最典型的是 gate_judge.py:100-102 拼 H 门 latch 细节时只读了 latch.after、没读 latch.phaseNow,于是当 latch 走 advisory 分支失败(play.cdp.cjs:1083,那支只带 phaseNow、不带 after)时,回喂里就说成 after=None,agent 根本不知道游戏卡在哪个 phase(本该是 playing),只能盲修。把反馈钉成结构、把『卡在哪个阶段』升为一等字段并在报 latch 失败时强制携带,这类丢字段就从结构上不可能发生。它要同时承载便宜档与 tier2 两档:核心字段两档同名同义(接口对称),tier2 独有的富游戏证据放 ext(内容不对称、Δ9③)。红线:字段不编码 tier 枚举,档位差异靠能力字段与 ext 表达,绝不出现 tier:cheap|tier2。消费方=W-S1 修复三单(gate_judge 产结构化反馈、middleware 注入续修)与 tier2 F-1 对齐。",
"type": "object",
"required": ["gameId", "passed", "failedGates", "items"],
"properties": {
"schemaVersion": {
"description": "契约版本标签(可选,建议 'verdict-feedback/1')。",
"type": "string",
"minLength": 1
},
"gameId": {
"description": "这份反馈对应哪局游戏(工程 id),供续修 agent 与台账定位。非空。",
"type": "string",
"minLength": 1
},
"passed": {
"description": "恒为 false:VerdictFeedback 是『没过门时才产』的反馈载荷,门全绿就不该有它(那时 agent 该去 finish 交付、而不是收反馈)。锁死 false 是为了从契约层杜绝『门绿了却还拼一份反馈踹回去续修』这种矛盾态——这与归一判定 GateJudgment(passed, failed_gates, feedback) 的口径一致:passed=true 时 feedback 不作回喂用。",
"const": false
},
"failedGates": {
"description": "未过门名清单(与 GateJudgment.failed_gates 同口径):便宜档=九门里 pass=false 的门名(A_boot..I_control);tier2 另带前缀——richGame:<门>(三联动/经济/latch 富游戏三门)与 finding:<severity>(P0/P1 对抗发现)。至少一项:没有未过门就不该产反馈。前缀差异是内容层扩展,不是 tier 枚举。",
"type": "array",
"minItems": 1,
"items": { "$ref": "#/$defs/gateId" }
},
"items": {
"description": "逐门结构化反馈(至少一项,与 failedGates 呼应):每个未过门一条,带它卡在哪、用什么驱动器判的、证据、疑似失败面、修复方向。这是本契约的主体——现行代码把这些拼成一段字符串(_cheap_verdict_feedback 逐门拼 hint+detail、verdict_feedback 逐门拼 detail+why),本数组把逐门信息结构化,字符串可由它派生(见 humanReadable),从而不再丢字段。",
"type": "array",
"minItems": 1,
"items": { "$ref": "#/$defs/feedbackItem" }
},
"evidence": {
"description": "信封级证据指针(可选):整份判分留下的证据根,供 agent 与排障回看。",
"type": "object",
"properties": {
"verdictPath": { "description": "本次九门/三层 verdict.json 落盘路径。", "type": "string" },
"tracePath": { "description": "本次生成轨迹 trace.jsonl 路径(对接 contracts/trace)。", "type": "string" },
"traceId": { "description": "贯穿生成任务链路的 traceId(既是反查键也是成本关联键,与 contracts/trace 的 traceId 同一个)。", "type": "string" },
"screenshotDir": { "description": "本局截图目录(first-paint.png / after-play.png 等取证图所在)。", "type": "string" }
},
"additionalProperties": true
},
"humanReadable": {
"description": "由 items 派生的人读中文回喂全文(可选,向后兼容现行字符串消费者):即 verdict_feedback / _cheap_verdict_feedback 现在产的那段话。留它是为了平滑过渡——续修 middleware 现在注入的是字符串,接线期可先并存;但它必须是 items 的派生投影、不得携带 items 里没有的信息(否则又回到字符串丢字段/夹带的老路)。",
"type": "string"
},
"ext": {
"description": "信封级扩展段(Δ9③):tier2 富游戏档独有、不进对称核心的整份反馈级证据放这里(如整局经济三个数汇总、findings 严重度分布、三层校验摘要),便宜档一般不写。接口对称(上面核心字段两档同名同义)、内容不对称(ext 各写各的、没有的绝不编造)。",
"type": "object",
"additionalProperties": true
}
},
"patternProperties": {
"^_": {
"description": "下划线开头的作者元数据(如 _note / _source),供人读与取样标注,消费方不依赖。放行任意值。"
}
},
"additionalProperties": false,
"$defs": {
"gateId": {
"description": "门标识:九门名(A_boot/B_uncaught/C_frame/D_render/E_live/F_wiring/G_input/H_progress/I_control),或 tier2 富游戏门 richGame:<tripleLink|economy|latch>,或对抗发现 finding:<P0|P1|P2>。",
"type": "string",
"pattern": "^([A-I]_[a-z]+|richGame:[a-zA-Z]+|finding:P[0-2])$"
},
"feedbackItem": {
"type": "object",
"required": ["gate", "driverType"],
"properties": {
"gate": {
"description": "这条反馈对应哪道未过门(取值见 $defs/gateId)。",
"$ref": "#/$defs/gateId"
},
"driverType": {
"description": "判这道门时用的驱动器族(PlaySpec.driver.type,如 key-cycle/tap-targets/paddle-intercept;用固定 inputs 序列判的填 input-sequence;A_boot 这类与驱动无关的门填 none)。为什么每条都必须带:续修 agent 要知道这局是怎么被玩的,才能判断『是玩法真坏了,还是判分的驱动方式没覆盖到』——现行代码知道 driver 却没把它随反馈带出去,本字段强制带上、避免归一重写时把它丢了。非空。",
"type": "string",
"minLength": 1
},
"phaseNow": {
"description": "卡在哪个阶段(游戏此刻的 phase,如 'playing'):真玩没驱动到终局时游戏停留的 phase。当本条报 latch 失败(下面 latch.pass=false)时强制携带——这正是修 gate_judge.py:100-102 丢 phaseNow 缺陷的一等字段:latch advisory 失败支(play.cdp.cjs:1083)只带 phaseNow、不带 after,旧代码只读 after 就把『卡在 playing』丢成了 after=None。非 latch 失败可省略。",
"type": "string"
},
"latch": {
"description": "终局 latch 判定细节(可选,仅 H_progress 类门带):真玩到没到终局态、到了有没有驻留。它出现且 pass=false 时,本条 item 必须带 phaseNow(见上)。",
"type": "object",
"required": ["pass"],
"properties": {
"pass": { "description": "是否玩到终局并驻留。", "type": "boolean" },
"advisory": { "description": "本次 latch 失败是否降为 advisory 不致命(有真进展的限时/无快速失败态类)。", "type": "boolean" },
"reason": { "description": "latch 判定原因(人读)。", "type": "string" },
"after": { "description": "驻留校验分支读到的终态 phase(play.cdp.cjs:1089 该支带 after 不带 phaseNow;与 phaseNow 互为两支,故两者都建模)。", "type": "string" }
},
"additionalProperties": true
},
"detail": {
"description": "这道门的人读细节(可选):如 F_wiring 的『期望前缀=… 实际 callCount=0』、H 门逐条断言 before/after、E_live 去重态数等(对应 _cheap_gate_detail / verdict_feedback 逐门 detail)。",
"type": "string"
},
"fixDirection": {
"description": "修复方向(可选,人读一句):这道门没过时该往哪修(对应 _CHEAP_GATE_HINTS 的门提示 / _RICH_CHECK_WHY)。",
"type": "string"
},
"evidence": {
"description": "本条门的证据指针(可选):console 日志、游戏运行日志、截图、状态快照等的路径或摘要,让 agent 据实修而非猜。",
"type": "object",
"properties": {
"console": { "description": "console 错误/日志(路径或摘要文本)。", "type": "string" },
"gameLog": { "description": "游戏运行日志(路径或摘要)。", "type": "string" },
"screenshots": { "description": "相关截图路径清单。", "type": "array", "items": { "type": "string" } },
"statePath": { "description": "玩前/玩后可观测状态快照(路径或内联)。", "type": "string" }
},
"additionalProperties": true
},
"suspectedSurface": {
"description": "疑似失败面(可选):文件/函数级的怀疑点清单,把『大概哪儿坏了』结构化给 agent,缩小续修搜索面。",
"type": "array",
"items": { "$ref": "#/$defs/surfaceHint" }
},
"ext": {
"description": "本条门的扩展段(Δ9③):tier2 富游戏门独有的逐门证据放这里(如经济门的三个数 measured/coinsTarget/winThreshold、finding 的 severity/issue/suggestion),便宜档九门一般不写。",
"type": "object",
"additionalProperties": true
}
},
"additionalProperties": false,
"allOf": [
{
"if": {
"properties": { "latch": { "properties": { "pass": { "const": false } }, "required": ["pass"] } },
"required": ["latch"]
},
"then": { "required": ["phaseNow"] }
}
]
},
"surfaceHint": {
"type": "object",
"properties": {
"file": { "description": "疑似出问题的文件(源工程相对路径,如 'src/systems/score.js')。", "type": "string" },
"symbol": { "description": "疑似出问题的函数/符号名。", "type": "string" },
"why": { "description": "为什么怀疑这里(人读一句)。", "type": "string" }
},
"additionalProperties": false
}
}
}