固化 Match-3 生产者、视觉、音频与双 Judge 证据闭包。 将《山海行纪》r1.1 绑定新的不可变 release,并以生产预检现场核验 bundle、Registry/2 和 25 项 Writer 快照。 同步地图1平衡锁值、跨游戏回归修复、验收契约与 SoT 证据。
202 KiB
date, topic, status, 上级, sot-impact, 关联, 图清单
| date | topic | status | 上级 | sot-impact | 关联 | 图清单 | |
|---|---|---|---|---|---|---|---|
| 2026-07-13 | cheap-gen-acceptance-v3-trusted-evidence-loop | 架构增补已批准、确定性 Match-3 fixture 与五个真实生成 Match-3 harness_fixture 的视觉、特效、音频专项机器证据已闭合至完整 AudioAudit 和 runner sidecar(更新至 2026-07-28;首款 game_content_gold 已签认,参照资产 `/2` 的显式策略冻结可信消费路径已闭合;fixture 人工真玩、Judge 稳定门、survivor live 自动路由、Audit/2 与 Proof/3 签发、总门及三批基线未闭合,生产 runtimeEligible 继续关闭) | docs/plans/2026-07-10-001-feat-生成线验收v2-测试agent替EGH-plan.md | 申报——修订生成验收门、游戏质量与爆火能力、生成引擎运行时、prompt治理、游戏内容金标五个 canonical topic;v3 已将便宜档玩法验收从测试 Actor 自裁改为结构化视觉操作、硬证据和双 Judge 保守合并,并为标准 Match-3 增加只读视觉归一与确定性交换枚举;校准与基线收口前不切生产口径 | docs/plans/2026-07-10-001-feat-生成线验收v2-测试agent替EGH-plan.md@5d0f3510 + game-runtime/games/_wg1-gen/_shared/playtest.cdp.cjs@5bcaf6ac + cheap-worker/cheap_verify.py@5bcaf6ac + cheap-worker/hard_genre_batch.py@8d851ea7 + tier2/config/generation.yaml@5bcaf6ac + game-cloud@5bcaf6ac;工作区有未提交修订,开工前重取防漂移基线 |
|
生成线验收 v3 · 可信证据闭环设计
0 核心关系
核心思想是把“看见什么、怎么操作、是否证明玩通”分开:离屏视觉工具只从 clean PNG 产生候选区域;标准 Match-3 再把可信棋盘归一为匿名同类并枚举可复算的交换对;Actor 只选择候选 ID 或交换对,runner 确定性解析并记录不可抵赖的动作、画面和事件;每掷由两个互相致盲的 Judge 读取同一份封存证据,确定性保守合并后才交给 rollGuard。Actor 与 Judge 均使用 MiniMax-M3,但会话、提示、上下文和输出目录完全隔离,任何模型都没有最终写权。
边界保持克制:A_boot、B_uncaught、C_frame、D_render 四门继续拦明显死;玩法闭环不再靠 canvas 变化、日志增长或模型一句 pass 推断,而由每个品类明确的 proof obligation 证明。CLI、Service create、modify 三路调用同一个验收编排器,最多允许一次 writer repair,之后必须终裁。
成功标准不是“模型认为成功”,而是每个 accepted 都能沿 actionId → frame → game/* event → obligation → Judge → rollGuard → mergeCandidate → finalPostguard 回到原始证据;历史 11 局、五品类 25 局和生产分布 20 局三批闸门在 mini-desktop 全部达标后,才允许从 v3_shadow 切到 v3。
1 意图与目标
v2 解决了旧 E/G/H 驱动器依赖私有取证契约的问题,却把行动和裁决交给了同一个测试模型。波 3 的 11 局复核暴露了新的自证循环:loopClosed 直接等于模型的 pass,局部动画和插件日志会被当成输入有效,经营局零订单、非遗局零成品、解谜局未归位、战斗局卡在升级页仍可能被接受。另一方面,模型推理期间游戏实时时钟继续走,节奏窗口和顾客耐心会在动作执行前耗尽,正常游戏也可能被误拒。
v3 的目标有五项:
- 每次接受都有品类闭环硬证,任何 summary、reason 或模型自报都不能替代事实。
- Actor 与 Judge 职责隔离;同为 M3 只解决供给问题,不允许共享会话或互相继承结论。
- 模型推理不消耗游戏时间,动作以 600ms 虚拟时间量子执行,时序类玩法测到的是操作能力而不是推理延迟。
- 三条生产入口采用同一状态机、同一字段和同一失败归因,创建与修改没有两套标准。
- 失败最多触发一次 writer repair;证据不足、测试器降级和环境故障不得被伪装成游戏缺陷送去盲修。
本设计继承 MVP 的生成成功率目标,但先加一条更高优先级的可信度约束:不带完整 proof obligation 的接受数一律不进入成功率分子。
2 边界
2.1 纳入范围
v3 覆盖便宜档创建、生产 Service 和 A11 modify 三路,从四门投影开始,到视觉候选、Actor 真玩、证据落盘、双 Judge consensus、二掷合并、一次修复、最终写回和后端 trace 为止。新链使用 playtest/3;现有 playtest/2 schema 与 validator 永久冻结,只读保留已有 native/shadow 证据。验收模式仍为 v3_shadow | v3,同时覆盖品类 proof obligation、失败归因和旧字段兼容。
mini-desktop 是唯一权威 E2E 环境。开发机单测、headless smoke 和历史 harness 结果只能用于排错,不能签发放量结论。权威验证必须用 mini-desktop 的真实 Chrome 打开产物,保留截图、事件和动作转写,并分别覆盖 CLI、Service create、modify。
2.2 不纳入范围
v3 不评价“多好玩”、美术品位、商业潜力或内容丰富度,这些仍归 L2 rubric 和真人抽玩。它不改 tier2 富游戏三门,不恢复 _forensicsView、play-spec 或 tap-targets,也不把品类语义重新塞进通用机械九门。
v3 不新增模型供应商。Actor 和 Judge 均使用 MiniMax-M3;独立性来自角色、会话、上下文和证据边界,而不是模型厂牌不同。后续若切换 Judge 模型,只能作为配置变更,不改变 playtest/3 契约。
3 方案
3.1 三路统一的证据流水线
flowchart LR
C[CLI 批跑] --> O[统一验收编排器]
S[Service create] --> O
M[A11 modify] --> O
O --> F[四门机械预筛]
F -->|通过| V[clean PNG 视觉候选]
F -->|失败| Z[finalPostguard]
V --> Q{标准 Match-3?}
Q -->|是| MS[匿名棋格归一与交换枚举]
Q -->|否| A[Actor 选择目标 ID]
MS --> A2[Actor 选择交换对]
A2 --> R
A --> R[Runner 记录硬证]
R --> P[ProofPackage]
P --> JA[Judge A]
P --> JB[Judge B]
JA --> JC[确定性保守合并]
JB --> JC
JC --> H[rollGuard]
H --> G[二掷与 mergeCandidate]
G --> Z
Z -->|accept / 不可修| D[终裁]
Z -->|verified reject 且可修| W[Writer repair 一次]
W --> O
V2[v2 历史证据] -. 仅离线重放 .-> H
D --> T[run-summary / verdict / trace]
三条入口只能调用一个接口:run_acceptance_v3(request) -> decision。操作请求固定携带完整 acceptance-request/2、brief 原文、artifactHash、evidenceRoot、acceptanceMode、幂等键和 repair 链引用;proof 身份与 interactionBinding 只从嵌套的 acceptance request 读取。interactionBinding 显式为 null 或完整 InteractionBinding/1,都会进入 acceptance request 的完整 canonical bytes 与 acceptanceRequestHash。接口、playtest/3 和 SingleRollFact 不再平铺 interactionProfileId、interactionRegistryVersion 或 interactionBindingHash。runner 所需的 CLI path 与标量只在 preflight 后由已核验对象确定性派生,不是另一份 request 身份,也不写成 playtest 顶层字段。编排器按“生成 artifactHash → 建 run → 四门 → 证据封存 → Judge → rollGuard → 可选二掷 → mergeCandidate → finalPostguard → 一次修复或写回”的顺序执行。相同幂等键、taskBindingHash 与 artifactHash 重入时只能返回已封存 decision,不得重跑并覆盖证据。
runner 启动浏览器前通过共用的 Python dirfd helper 一次性读取 staged gameDir 的全部普通文件,并只通过本机内存快照服务向浏览器供给这些字节。artifactHash 固定使用 artifact-snapshot/1:先写域标签,再按 UTF-8 路径字节序排列文件,每项写 8 字节大端 path 长度、path、8 字节大端内容长度和内容;不再用可把 a+bc 与 ab+c 混成同一输入的裸拼接。根和每级目录、最终文件都以 openat + O_NOFOLLOW 打开并核对 device/inode,先用 fd fstat 核普通文件与 128MiB 总预算,再按已核大小读取,读后复核 device/inode/size/mtime/ctime;祖先目录或最终文件换 symlink、读中截断或改写、超限稀疏文件都不能改变已打开目录描述符所绑定的读取对象。Node 对 helper 的长度清晰输出再次复算 hash。浏览器、截图和 Judge 在本掷中不再读取活目录;“运行前后各算一次目录 hash”只能发现部分漂移,无法阻止“改写、加载、恢复”的 TOCTOU,不能承担内容绑定。活目录随后变化不改变本掷事实,发布边界必须重新核对待发布目录的 artifactHash 与已接受 decision 一致。
四门只回答产物是否成功装载、是否出现未捕获异常、引擎是否掌帧、是否存在真实渲染。四门通过后,Actor 获得 brief、当前截图、合法动作协议和上一动作的客观结果;它不接触源码、生成对话、旧 verdict、proof obligation 的裁决结果,也不能产出最终 pass。
runner 是证据的唯一生产者。它执行动作、控制虚拟时间、记录动作前后帧、保存完整事件流,并把事实投影到品类 proof obligation。Judge 接收只读 JudgePackage,不接收 Actor 的推理、summary、feedback 或自评。确定性 rollGuard 在每掷后只产 rollOutcome,merge 只产 mergeCandidate;只有 finalPostguard 有权写 decision.outcome、accepted 和所有兼容字段。最终接受公式固定为:
accepted = floor.pass
AND proof.requiredObligations 全部 satisfied
AND proof 无未解释矛盾
AND judgeConsensus.decision = accept
AND actor / runner / 两个 judge / consensus 均无错误
AND finalPostguard.pass
3.2 流程阶段与结果四态
playtest/3 延续执行进度与业务结果正交的口径,禁止再用一个“状态”同时承担两种语义:
phase = PRECHECK | COLLECTING | JUDGING | DECIDED
outcome = accept | reject | inconclusive | tester_error
accepted = (outcome == accept)
每个验收 run 只有四个 phase;修复不是第五个 phase,而是终裁后创建一次全新的 run。旧 run 的证据只读保留,不能被覆盖。outcome 只在 DECIDED 由 finalPostguard 写入:reject 表示硬证已经证明可复现的产物缺陷;inconclusive 表示合法证据不足或互相矛盾;tester_error 表示 Actor、runner、Judge、schema、图像或环境故障;accept 表示全部接受条件成立。
stateDiagram-v2
[*] --> PRECHECK
PRECHECK --> COLLECTING: 四门通过
PRECHECK --> DECIDED: finalPostguard(mechanical)
COLLECTING --> JUDGING: 证据包封存
COLLECTING --> DECIDED: finalPostguard(tester_error)
JUDGING --> DECIDED: rollGuard、mergeCandidate、finalPostguard 完成
DECIDED --> PRECHECK: 仅一次 writer repair 后新建 run
DECIDED --> [*]: 四态 outcome
| phase | 允许的工作 | 离开条件 |
|---|---|---|
PRECHECK |
读取构建指纹并运行 A/B/C/D 四门 | 四门全绿进入取证;否则机械失败终裁 |
COLLECTING |
Actor 操作,runner 控时并生成动作、帧、事件和义务证据 | 单掷结束并封存 ProofPackage;仪器异常进入 tester_error |
JUDGING |
两个独立槽核同一 JudgePackage,确定性 consensus 后由 rollGuard 决定是否二掷;merge 只产候选;finalPostguard 终裁 | 得到并写入四态 outcome |
DECIDED |
finalPostguard 写回权威结果,决定是否允许唯一一次 repair | accept/reject/inconclusive/tester_error,或以新 run 回到 PRECHECK |
状态转换必须带 runId 和产物哈希。repair 后代码变化会产生新哈希,旧 ProofPackage 自动失效;任何跨哈希复用截图或事件都属于协议错误。
3.3 playtest/3 协议
playtest/3 是结构化目标选择、动作事实、证据义务和双 Judge 裁决的单一接口。全文落在 evidence/playtest-v3/<runId>/,汇总文件只保存引用,不复制或改写原始证据。playtest/2 不增加字段、不放宽 schema;读取旧证据时按原 validator 验证,不能经适配器伪装成 playtest/3 accept。
| 字段 | 含义 |
|---|---|
schemaVersion |
固定为 playtest/3 |
runId / parentRunId |
当前验收标识;repair 后新 run 通过 parentRunId 指回原 run |
gameId / genre / proofProfileId / proofRegistryVersion / taskBindingHash / acceptanceRequestHash / artifactHash / briefHash |
被测对象、当前生成任务、可信证明 profile 与不可变输入指纹;interaction 身份不在此平铺,只经 acceptanceRequestHash 和 SingleRollProof/2→Resolution 闭包回读 |
acceptanceMode / evidenceMode |
v3_shadow / v3 / historical_replay 与 native / legacy-adapted |
phase |
PRECHECK / COLLECTING / JUDGING / DECIDED |
outcome |
accept / reject / inconclusive / tester_error;仅 DECIDED 存在 |
environment |
host、Chrome 版本、固定 390×844@1 视口、必须等于顶层 artifactHash 的 buildRef、固定 CDP 600/100/3000 虚拟时间配置 |
floor |
A/B/C/D 原始结果、测量值和证据引用 |
actor |
模型、角色提示版本、隔离会话标识、requested/actual game seed、policy seed;不得含最终裁决 |
actions[] |
actionId、ActorSelection 请求、TargetSet/guide/resolver 的完整 ref/hash、规范化坐标动作、合法性、重试次数、preFrameHash/preEventSeq、dispatch receipt、virtual-time budget、timeAdvance、postFrameHash/postEventSeq、事件区间 |
events[] |
单调 seq、虚拟时间、namespace、producer、event type、payload/payloadCanonical/payloadHash、关联 actionId;完整保存,不裁成日志尾 |
proofObligations[] |
义务编号、是否必需、状态、权威 sequenceRefs、其扁平兼容投影和矛盾列表 |
firstPlay |
页面可交互时间、首次输入因果反馈、闭环完成时间及其 proof 引用 |
rolls[] |
每掷 requested/actual seed、证据包 ref/hash、JudgePackage ref/hash、Judge A/B ref/hash、consensus ref/hash、rollGuard、rollOutcome、错误和成本 |
merge |
二掷是否触发、触发原因、mergeCandidate、胜出证据、冲突和人工复核原因;无最终写权 |
judge |
带可空 sourceRollId + consensusRef/hash 的 JudgeConsensus/1 兼容摘要:两槽独立性检查、逐槽结果 hash、逐义务保守合并、冲突和 consensus decision |
finalPostguard |
覆盖四门失败、单掷、二掷、错误和 repair 后新 run 的最终确定性校验;唯一 decision 写权 |
decision |
outcome、accepted、失败层、失败子类、repair 次数和权威原因 |
compatibility |
向旧 judge、playtest、failureLayer、trace.playtest 的投影结果 |
派发协议继续使用坐标化 tap、key、wait、drag,但 Actor 不再直接输出裸坐标。ActorView 升为 ActorView/3,模型只输出 ActorSelection/1:tap 选择一个当前帧候选 ID,棋盘选择候选 lattice 的 row/column,drag 选择起止候选;key 与 wait 保持原形。runner 校验 targetSetHash、候选 ID、行列和 gesture 后,确定性解析为现有坐标动作再派发。模型输出裸坐标、旧 targetSet、未知候选、越界 cell、退化 drag、非法 JSON 或违反当前场景能力时,runner 保持当前帧和虚拟时间不动,把结构化错误返回 Actor。每个选择最多重试两次;第三次仍非法,该掷 outcome=tester_error、subtype=target_protocol_exhausted,不能归因游戏,也不能触发 writer repair。
ActorSelection/1 只允许以下四个互斥形态,所有对象均 additionalProperties=false:
| type | 精确字段 | 约束 |
|---|---|---|
| tap | schemaVersion,type,targetSetHash,target |
target={id} 或 {id,cell:{row,column},subAnchor};region 只允许 {id},lattice/grid 必须带 cell |
| drag | schemaVersion,type,targetSetHash,from,to,ms |
from/to 使用同一 targetRef 结构;ms 固定 600;解析后起终点不得相同 |
| key | schemaVersion,type,key |
key 必须属于当前 safeKeys;不得携带 targetSetHash 或 target |
| wait | schemaVersion,type,ms |
ms 为 100–3000 整数;不得携带 targetSetHash 或 target |
targetRef.id 必须属于当前 TargetSet;row/column 从 1 起并受候选维度约束。subAnchor 只允许 center/north/south/east/west/northwest/northeast/southwest/southeast 九值,region 禁止 subAnchor。parser 先验证结构,resolver 再按实际 target kind 验证语义;两层任一失败都不派发。
合法动作必须封存 timeAdvance,字段固定为 requestedBudgetMs、plannedFrames、executedFrames、callbacksRun、carryMs 和 ok;ok=true、requestedBudgetMs 等于动作预算且 plannedFrames=executedFrames 才能进入 post 取证。非法动作的 timeAdvance 固定为 null。该字段是“模型等待不推进、合法动作精确推进”的权威证据,不能只留在 runner 内部调试日志。
Actor 每轮只看到 runner 生成的 ActorView/3:brief、currentFrameRef、legalSelections、当前 VisualTargetSet/1 的可见目录、上一动作的 selection/normalized/valid、pre/post frame refs、完整 game/* delta、candidate-only objectiveProgress、protocolErrors 和 remainingBudget。Actor 看不到候选的真实坐标、score、生成阈值或 proof 语义;完整 bounds、safePoint 和 generator 配置只在 runner 审计目录。Actor 原文不得回灌下一轮 history、ProofPackage 或 JudgePackage;history 只能由上述客观字段生成。义务候选齐备时 runner 自动封存,预算耗尽则进入 judging,Actor 没有任何 verdict 或 stop-and-pass 变体。
两个 Judge 只读取同一份封存后带 hash 的 JudgePackage:brief、proofProfileId、义务注册表版本、artifactHash、动作规范化事实、post-frame refs、完整 game/* events 和候选 sequenceRefs。runner 把当前 profile 事件标为 profile-proof,其它已注册 profile 事件标为 cross-profile-observation;两类都进入 JudgePackage,后者可证明全局 off_brief,但在候选解析前被排除,绝不能满足当前义务。它不得包含 Actor 原始文本/history、视觉候选目录、旧 verdict、生成记录、兼容字段或任何既有结论。Judge A 先按逐义务事件到截图检查,Judge B 先按截图终态与矛盾到事件检查;两者规则与 schema 相同,但 API client、session、policy seed、prompt artifact、输出目录和 raw 文件完全隔离,且都看不到对方输出。
Actor selection、目标解析和两份 Judge 输出都由 schema 强制。图片传输健康只认请求 image manifest、实际字节 hash、provider request id 和响应关联,不认模型自报的 canSeeScreenshot;模型是否真正理解画面只由 prompt_eval_gold 行为校准。rollGuard 与 finalPostguard 复用同一组机械检查:所有 required obligation satisfied;每个引用存在且 hash/artifactHash 一致;每项同时引用同一动作区间的 post screenshot 与 game/* event;contradictions 和 blocking problems 为空;Actor/runner/两槽 Judge/consensus 无错误;consensus decision=accept。任何一项不成立都不能接受,两个 Judge 同时 accept 也不能覆盖 finalPostguard。
3.3.1 视觉候选与目标执行
VisualTargetSet/1 是操作辅助,不是“可信可交互目标”。仅凭 clean PNG,runner 无法证明一块区域真的有 hitbox;这里的可信含义只限于输入字节、候选集合、导览图和解析结果有 hash 绑定,不能把候选存在、被选择或派发成功当成游戏响应、proof obligation 或质量结论。helper 崩溃、hash/schema/越界和 resolver 的确定性失败归 tester_error;合法 selection 已派发但持续无响应时,生产黑盒无法区分 proposer 错框、Actor 选错、resolver 偏差或游戏缺 hitbox,固定归 inconclusive/interaction_unresolved,不得触发 gameplay reject 或 writer repair。只有带人工区域 mask 或合法 cell 的 eval 才能进一步归因 proposer、selection 或 resolver。
每个 distinct clean frame 只生成一次 TargetSet,输入固定为同一份已校验 PNG 字节,禁止读取 DOM、CSS、Accessibility Tree、事件监听器、源码、bundle、template route、genre、brief、proofProfile、ctx.event 或 Writer 私有 hitbox。离线 helper 使用锁版 opencv-python-headless 的轮廓、连通域和形态学能力,结果再由项目代码确定性排序、去重和裁剪;生产与 eval 必须调用同一 helper。候选由三层组成:
| 候选 | 用途 | 解析方式 |
|---|---|---|
RegionTarget |
按钮、图标、圆形目标、卡牌等闭合视觉区域 | bounds 内距视觉边缘最大的稳定点;失败时取内缩中心 |
LatticeTarget |
Match-3、2048、棋盘和规则重复布局 | Actor 选择 row/column,runner 解析单元中心或有限 subAnchor |
SpatialGridTarget |
透明 hitbox、自由画布、区域/lattice 漏检的永久降级面 | Actor 选择 grid cell 与有限 subAnchor;禁止连续比例或任意偏移 |
TargetSet 必须包含 sourceFrameRef/sourceFrameHash、generator.id/version/configHash、完整 targets、targetSetHash 和绑定 sourceFrameHash + targetSetHash + guideHash 的 target guide。Actor 可见目录只含 targetId、kind、允许 gesture 和 lattice/grid 维度,不含 bounds、safePoint 或 proposal score。完整 TargetSet 与 Actor 可见投影是两个边界:前者保留全部稳定 ID 供 hash、审计和 resolver 使用;后者只隐藏确定性的几何重复项,不重排 ID,也不改 targetSetHash。Actor 返回时 runner 再核对当前 frozen frame hash 与 targetSetHash;过期、未知 ID、越界 cell、gesture 不支持或解析点越出 viewport 均不派发、不推进虚拟时间。
opencv-visual-targets@1.0.1 使用版本化的 generatorConfig/1,不散落魔数:region 的 minArea=64、minSide=24、maxAreaRatio=0.35、NMS IoU=0.65、上限 24;lattice 只接受 3–12 行、3–12 列,间距变异系数不高于 0.12、候选尺寸变异系数不高于 0.15、轴残差不高于 3px、已观察 cell 覆盖不低于 70%,上限 4。observedCells 保存直接支撑轴推断的行优先唯一子集,覆盖率必须与 coveragePermille 一致且每行每列至少有三个支持点;它不代替后续逐格分类,正式 Match-3 感知仍须独立产出 64/64 类别。spatial grid 固定一个 g01,8 列 × 17 行,使用九个有限 subAnchor。总目录最多 29 个顶层 target,lattice 接受后抑制完全落在其 bounds 内的子 region,避免棋盘产生几十个重复标签。ID 按 kind=lattice,region,spatial_grid、中心 y/x、bounds 字典序稳定生成,禁止依赖 OpenCV 返回顺序。
Actor 可见投影在稳定 ID 生成后执行两条收窄规则。一个 region 若完整吞入至少两个面积小三倍以上的子 region,视为分组父容器,不进入 catalog 和 guide;两个 region 若至少 95% 套叠且面积比不超过 5,优先保留完整 contour,删除量化 connected-component 色块,同源时保留较大边界。规则只减少模型眼前的等价框,不删除完整 TargetSet 中的 target。g01 始终保留并继续标 fallbackOnly=true;guide 先画降级网格,再用 clean 像素恢复 primary 区域,网格线不得穿过已发现的紧框控件。每个 region 的 ID 标签放在离 safePoint 最近的可用边界外,以黑底青色 leader 直接连接黄色黑边 safePoint;标签不得覆盖黄点,也不能再只悬在 bounds 左上角让重叠框产生错误绑定。
targetSetHash 固定为 SHA256(domainLabel + stableJson({schemaVersion,sourceFrameHash,viewport,generator,targets})),不包含自身、sourceFrameRef、guide 或其它运行时路径;同 PNG 字节与 generatorConfig 必须跨 run 产生相同 canonical target 内容和 hash。sourceFrameRef 只保留在 TargetSet manifest 外层,guide manifest 另封 sourceFrameRef/hash + targetSetRef/hash + guideRef/hash + guideVersion。prompt_eval_gold 门分别报告 region/lattice primary coverage 与 spatial fallback coverage;永久 grid 不能计入 primary coverage,避免“总有一个格子”造成假绿。
动作账同时保存三层可回读事实:request.parsed 为 ActorSelection/1,normalized 为现有坐标 tap/drag/key/wait,targetResolution 使用条件联合类型。合法 tap/drag 为 status=resolved,包含 targetSetRef/hash、sourceFrameRef/hash、guideManifestRef/hash、resolverVersion、原 selection 和 resolvedPoints;drag 分别标 from/to,lattice/grid 保留 cell 与 subAnchor 到点的映射。合法 key/wait 为 {status:"not_applicable"}。parser 失败的 attempt audit 记 targetResolution=null;resolver 失败记 status=failed,保留可得的 TargetSet/source/guide 引用、selection、resolverVersion 和结构化 error,resolvedPoints 为空,normalized/timeAdvance 固定 null。只有成功动作进入正式 actionRecord;失败 attempt 在同帧审计目录和 protocolErrors 中可回读。CDP、isTrusted 输入归因、虚拟时间与 proof 只消费 normalized action;TargetSet、guide、proposal source 和 score 禁止进入 ProofPackage/JudgePackage。被测游戏即使在画面里伪造 targetId 或指令文字,也只能影响 Actor 选择,不能制造 accept。
每个 roll 强制封存 judgePackageRef/hash、judgeARef/hash、judgeBRef/hash 和 judgeConsensusRef/hash;A/B ref 分别指向 raw、parsed 与 normalized result hash 的槽目录清单,consensus 文件引用两槽 hash 并保存 independenceChecks。顶层 judge 只是兼容投影,必须带 sourceRollId 与 consensusRef/hash;一掷时镜像 roll-1,二掷时只镜像 finalPostguard 实际采用的 source roll,冲突无 source roll 时投影 consensus decision 与 conflicts,绝不能任选更有利的单槽或单掷。
2026-07-14 的首个 /private/tmp 真 M3 探针只用朴素 contour/component 加编号,五个 Actor prompt_eval_gold 行为仅 2/5:runner restart 与 2048 正确,shop 选错卡片,Match-3 选到计数文字,Simon 输出字段不合协议。这证明“把坐标换成编号”不是解决方案。实施第一门必须分别测候选覆盖率、Actor 选择准确率、解析正确率和真实派发响应率;区域+lattice+空间降级未达到 prompt_eval_gold 门时,不得接生产 Actor,也不得用 prompt 措辞掩盖 proposer 缺陷。
3.3.2 标准 Match-3 的专用视觉求解
Match-3 的验收目标是证明玩家能完成一次真实交换,不是考 Actor 能否把六十四个棋格逐个命名后再心算全盘。最新两次完全相同的 3.0.4 请求中,MiniMax-M3 分别选择了 r1c5 和 r7c6;把画面中的橙红宽松视为同一类后,两次棋格识别仍只对 40/64 和 31/64。模型随后在各自看错的棋盘上完成了自洽演算,因此继续增加提示词不能修复输入事实已经错误的问题。标准 Match-3 改由 runner 在 Actor 之前完成“同类棋格归一与合法交换枚举”,Actor 只在可执行交换对中选择,不再承担全盘识别和规则搜索。
这条专用路径只在两个条件同时满足时启用:可信编排器已为当前任务指定版本化的 match3.orthogonal-swap-v1 交互规则,当前 clean frame 中存在通过 VisualTargetSet/1 指标门并完成 source frame、targetSet 和 lattice hash 绑定的棋盘候选。这里的绑定只证明候选来源可追溯,不证明棋盘内容或游戏规则正确。交互规则由独立 registry 管理,编排器在 Writer 前把完整 InteractionBinding/1 嵌入 acceptance-request/2,builder provenance 逐字镜像;acceptanceRequestHash 覆盖整个嵌套对象。runner 的 path 和标量只从核验后的对象派生,不形成另一组 request 字段。Writer、Actor 和被测游戏不能选择或改写交互 profile;repair 新 run 逐字继承同一 interaction binding。BoardProjection、SwapSet 和 actionGroup 仍携带从 verified binding 派生的三个 interaction identity 字段,任一缺失或漂移归 tester_error/profile_contract_error,不得退回通用规则猜测。
solver 只读取 frozen clean PNG 与 lattice 的行列几何,不读取 DOM、CSS、源码、事件监听器、模板私有状态、label、brief 文案或 guide 叠加图。规则只覆盖正交相邻、不同视觉类别的两个棋格交换后形成新的横向或纵向连续同类段;特殊块、障碍、对角交换、自由移动、连锁规则和任意非标准变体继续走通用 Actor,不得把这一套规则强套给其它解谜游戏。
视觉求解分成感知和规则两步。感知只回答哪些棋格在当前画面上属于同一类,不回答颜色名、图标名或游戏语义;规则层只消费匿名类别,枚举交换并给出可复算证明。两步均无随机采样,同一 PNG、TargetSet、lattice 和版本化配置必须跨进程产生逐字相同的结果。
2026-07-16 的 fresh 校准把前景覆盖门从 400..800 调整为 380..850、单通道 MAD 上限从 18 调整为 64。瓷器样本在旧门下只有 39/64 可读,失败格覆盖率为 387..400,带纹理图标的最大 MAD 为 64;新门得到 64/64、六类且低/标称/高三档各 16 个合法 pair。糖果样本虽然每格覆盖率均为 826,放宽后仍只聚成一类并触发 class_count_out_of_range,因此没有被误放行。阈值由 configHash 绑定,旧证据不重解释。
Match3BoardProjection/1 是 runner 内部的只读棋盘投影:
| 字段 | 含义与约束 |
|---|---|
schemaVersion / sourceFrameHash / targetSetHash / latticeId / dimensions |
固定输入身份;任一缺失或无法对账都使投影失效 |
interactionProfileId / interactionRegistryVersion / interactionBindingHash |
从 verified InteractionBinding/1 派生的只读交互规则身份,必须与 request/provenance 嵌套对象、binding 文件和 runner 派生参数一致 |
classifier.id/version/configHash |
逐格裁切、特征与匿名聚类的版本化实现和配置;禁止散落阈值 |
cells[] |
按 row、column 排序的 VisualCellClass,必须完整覆盖 lattice |
projectionStatus |
resolved / indeterminate;只要歧义可能改变合法交换集合,就必须是 indeterminate |
projectionHash |
对上述 canonical 内容计算的 SHA-256,不包含运行时路径和自身 |
每个 VisualCellClass 固定包含 cell:{row,column}、从原 clean frame 确定性裁出的 cropHash、state、classId、confidencePermille 和 alternatives。state 只能是 classified / ambiguous / unreadable;只有 classified 才有非空 classId,其值按行优先首次出现顺序编号为 vc01...,只表示本帧内的视觉同类匿名簇。confidencePermille 是“最佳类别距离与次佳类别距离之间的归一化间隔”,不是概率,也不能解释成模型正确率;距离函数、量化公式、判定阈值、允许扰动与 selection overlay 归一规则全部进入 classifier configHash。alternatives 只在 ambiguous 时按间隔和 classId 固定排序。实现不得保存或比较硬编码 RGB、品类颜色名、棋子文案,也不得把模型说出的颜色名当成类别真相。第一版要求全部棋格可判定;任一格 ambiguous/unreadable,或聚类在配置声明的允许扰动内会改变交换集合,整个投影保守退出。
规则层从 resolved 投影生成 Match3SwapSet/1。它携带 sourceFrameHash、targetSetHash、latticeId、三个 interaction identity 字段、projectionHash、solver.id/version/configHash、beforeRuns、有序 candidates[]、status 和 candidateSetHash。status 只能是 resolved / no_candidate / indeterminate;空候选不等于游戏坏,只表示当前画面没有可执行交换,不能直接形成 reject。
每个 SwapCandidate 包含稳定 candidateId、无序 pair、pairKey、交换前两个匿名 classId、newRuns[] 和 candidateHash。pair 的两个端点必须正交相邻且 classId 不同,统一按 (row,column) 字典序保存,pairKey 由规范化后的两个端点生成,因此 A↔B 与 B↔A 是同一候选。solver 先计算交换前全部最大连续段,再交换 pair 并重算两个端点所在横行与纵列;只有交换后出现至少一个此前不存在、长度不小于 3、且包含至少一个交换端点的最大连续段,才产生候选。newRuns[] 逐条保存 axis、classId 和按轴排序的 cells;四连、五连和十字交叉分别按最大连续段 canonical 化,已有三连不能冒充新三连。任何人都可只凭 BoardProjection、pair 和规则版本复算候选与证明。
flowchart LR
F[冻结 clean frame] --> L{可信 lattice 与标准交换规则}
L -->|否| A[通用 Actor]
L -->|是| C[匿名棋格归一]
C -->|不可判定| U[诊断性通用 Actor或专用视觉模型]
C -->|可判定| S[确定性枚举 SwapCandidate]
S -->|无候选| I[inconclusive]
S -->|有候选| V[ActorView 只给 candidate pair]
V --> P[Actor 选择 pair]
P --> T1[真实浏览器 tap 1]
T1 --> K{棋盘身份仍有效}
K -->|否| I
K -->|是| T2[同一 pair 的 tap 2]
T2 --> E[新 frame + game event + obligation]
E --> J[双 Judge 与 finalPostguard]
现有 ActorView/3 与 ActorSelection/1 都是严格 schema,不能静默塞入 pair 字段。实施时保持顶层 playtest/3 不变,contract-first 新增 ActorView/4 与 ActorSelection/2。ActorView/4 对普通场景保持原投影;标准 Match-3 只增加 interactionCandidates.match3Swaps,每项只含 candidateId、latticeId 和两个 endpoint,并带 candidateSetHash,不暴露 VisualCellClass、confidence、newRuns、solver 证明或任何 verdict。
ActorSelection/2 继承原有 tap/drag/key/wait 四种形态,并增加字段严格的 swap_pair:schemaVersion,type,targetSetHash,candidateSetHash,candidateId,firstEndpoint。schemaVersion 固定为 ActorSelection/2,type 固定为 swap_pair;firstEndpoint 使用 {id,cell:{row,column},subAnchor:"center"},必须逐字命中 candidate 的 latticeId 和其中一个 endpoint。对象禁止额外字段。Actor 逐字复制两个 hash 与 candidateId,只选择先点哪一端;runner 从候选集确定 secondEndpoint,不允许 Actor另选第二格,也不允许把 tap、drag 或裸坐标伪装成同一交换计划。
版本兼容按显式矩阵执行,validator identity 与 Prompt registry entry 一并进入审计包:
| ActorView | 允许的 selection | validator | 使用范围 |
|---|---|---|---|
ActorView/3 |
ActorSelection/1 |
actor-selection-v1 |
现行普通路径与 Match-3 solver shadow;不得出现 swap_pair |
ActorView/4 普通场景 |
ActorSelection/2 的 tap/drag/key/wait |
actor-selection-v2 |
enforce 切换后的统一 Actor 投影 |
ActorView/4 标准 Match-3 resolved |
仅 ActorSelection/2.swap_pair |
actor-selection-v2 + match3-pair-resolver |
pair 级行动计划 |
View/Selection 版本不配、Prompt 声明与实际 validator 不同、View/4 Match-3 返回普通 tap/drag、View/3 返回 swap_pair 都在派发前归 tester_error/actor_protocol_version_mismatch。shadow 阶段仍由 View/3 + Selection/1 执行真实动作,BoardProjection/SwapSet 只旁路审计;只有 View/4、Selection/2、pair resolver 和 gold 同批过门后才能一起切 enforce,不允许分步混用。
一个 swap_pair 选择在动作账中展开为同一 actionGroupId 下的两个原生 tap。组记录固定包含三个 interaction identity 字段、candidateSetHash、candidateId、初始 sourceFrameHash/targetSetHash、规范 pair、firstEndpoint、secondEndpoint、两个 actionId、boardIdentityCheckRef/hash 和 state=awaiting_first | awaiting_second | completed | aborted。
第一下派发后 frame hash 正常会因选中描边而变化,新的 TargetSet hash 也可能随像素候选变化;它们不能再与初始值逐字相等作为第二下条件。runner 必须从 post-first clean frame 重新生成 TargetSet、定位等价 lattice、重做匿名类别投影,并封存 BoardIdentityCheck/1。该检查包含 actionGroupId、interaction binding、初始与 post-first 的 frame/TargetSet/lattice 引用及 hash、两个 lattice 的 dimensions/rowCenters/columnCenters、初始与新匿名类别等价矩阵 hash、overlayNormalizer.id/version/configHash、result=equivalent | changed | indeterminate、reasons 和 checkHash。类别比较按“哪些 cell 互为同类”的等价关系进行,不依赖本次重新编号得到的 classId 字面相等。
版本化 overlay normalizer 只允许处理 firstEndpoint 上已校准的选中描边、亮度环或轻微缩放,并须证明去除 overlay 后的匿名类别关系不变;未知高亮、遮挡或扰动固定为 indeterminate。新旧 frame/TargetSet hash 不同本身不 abort;只有 lattice 行列或中心几何超出版本化容差、匿名类别等价关系变化、无法可靠去除 overlay、业务事件表明棋盘已提前推进,才令计划 aborted,第二下不得派发。result=equivalent 时,runner 使用 post-first TargetSet 中的等价 lattice 解析 secondEndpoint,不能继续用初始帧坐标。第二下不匹配、重复第一端、跨 pair、旧 candidateSet 或越界同样属于协议错误,不能退回任意点击。
同一 roll 最多允许一次“重置选中态后重新感知与重选”。旧 actionGroup 先 sealed 为 aborted,不能改写;只有 interaction profile 明确声明并经真浏览器 prompt_eval_gold 校准的 selectionReset 动作时,runner 才可执行该动作,默认标准动作为重新点击 firstEndpoint。reset 是独立原生 action,消耗一个 600ms 动作量子,并须得到无交换提交事件、棋盘类别关系恢复可判定的新 frame。随后 runner 从新 frame 生成新的 TargetSet、BoardProjection、SwapSet 和 candidateSetHash,Actor 只能创建新的 actionGroup,旧 candidateId 不得沿用。进入恢复前 remainingBudget 必须足够容纳 reset 加新的双 tap,专用视觉模型成本也必须原子预留;条件不满足、profile 没有 reset、reset 后仍不可判定或新 actionGroup 再次 aborted,固定终止本掷为 inconclusive/board_identity_unresolved。每掷最多两个 actionGroup,不再调用 Actor、不继续推进,也不以新 seed 偷换同一掷;需要第二掷时交给既有 rollGuard 决定。
solver 和 pair 只证明“这组动作按当前可见棋盘规则值得尝试”,不证明游戏接收了交换,更不证明玩法通过。两个 tap 仍须由真实浏览器派发并各自记录 pre/post frame、事件区间和虚拟时间;第二下之后必须看到新的 frame 与同一动作组可归因的 game/* 业务事件,并由品类 obligation、双 Judge 和 finalPostguard 交叉验证。solver 的 BoardProjection、候选和证明只能留在 Actor/runner 审计目录,禁止进入 ProofPackage/JudgePackage、满足 obligation、触发 writer repair 或写 accept/reject。
标准 Match-3 的生产业务事件固定为同一第二 tap 同步栈内依次发出的 puzzle.swap-committed 与 puzzle.match-formed。前者 payload 必须且只能包含 moveId、规范化 pair:[{row,column},{row,column}]、boardRevisionBefore、boardRevisionAfter;pair 按与 SwapCandidate 相同的字典序保存,revision 为同一局内单调整数。后者 payload 必须且只能包含同一 moveId、runs[]、去重排序的 matchedCells[] 和 matchedCount;每个 run 只含 axis 与按轴排序的 cells,长度不小于 3,matchedCount 必须等于 matchedCells 长度。两事件都由 runtime game-event/1 信封自动附上第二 tap 的 actionId,游戏不得自填 actionId 或 actionGroupId。
runner 用第二 actionId 把两事件机械关联到 sealed actionGroup;完整 actionGroup 只留在 runner 审计层,不进入 ProofPackage/JudgePackage。候选解析先以 actionGroup 完整、BoardIdentityCheck 通过、两事件 actionId 都等于 secondActionId、moveId 相同且事件顺序相邻、swap pair 等于规范 pair、boardRevisionAfter 大于 before、match-formed 至少有一个 run 与三个 matched cell作为机械前置条件。通过后,puzzle.match3-valid-swap 只向 proof 输出两个 obligation step:swap-committed 与 match-formed;两步的 actionRef 都是 secondActionId,postFrameRef 都是第二 tap 的 post frame,各自 eventRef 只指向对应业务事件。candidateId、candidateSetHash、BoardProjection、BoardIdentityCheck 和 solver beforeRuns/newRuns 一律不投影给 Judge。
puzzle.match3-valid-swap 在 puzzle.match-board 中固定 defaultRequired=false。puzzle.match-board 同时覆盖数字滑块、连线和其它棋盘解谜,不能把 Match-3 专用义务强加给整个 proof profile。只有 request、provenance、runner 参数与独立 InteractionBinding/1 四处身份核验通过,且 interactionProfileId 精确等于 match3.orthogonal-swap-v1 时,义务解析器才把它提升为 required。brief 关键词、Writer 输出、游戏事件、Actor 选择和 solver 发现候选都没有提升权。
post frame 必须显示棋盘已变化以及与交换结算一致的可见反馈。Judge 只看两个 proof step 的动作、事件和 post frame;事件声称成组但画面仍停在首 tap 选中态、pair 不同、moveId 不同、事件异步失去 actionId、matchedCount 对不上或缺任一事件,义务都不能 satisfied。连续合法派发仍没有这组事件或可见结果时,固定归 inconclusive/interaction_unresolved,runner 不从像素变化反推业务成功。
当前 Match-3 prompt_eval_gold 只检查第一下是否落在二十二个合法端点之一,无法证明 Actor 选择了正确搭档:同一端点可能连接多个相邻格,其中只有部分交换有效。新版 prompt_eval_gold 必须保存完整匿名棋格矩阵和十六组无序合法 pair;pair 由人工双人复核并用一份不导入生产 solver 的最小 reference oracle 独立复算,生产 solver 只能与这份 sealed pair gold 对比,不能自己生成自己的期望。endpoint 集只作兼容观察,不再决定行为正确性。行为门要求 Actor 选择合法 candidateId,runner 实际执行同一 pair 的两端,第二下后出现可归因的新三连结果。第一下碰巧属于某个合法端点、第二下换到其它相邻格、交换后无新三连、已有三连被当成新三连,全部不得计为成功。
无法可靠聚类时不得猜。runner 可以让通用 Actor继续操作以收集诊断证据,也可以在原子成本预留内升级经过 prompt_eval_gold 校准的专用视觉模型;专用模型最多补充逐格匿名类别,交换枚举仍由确定性 solver 完成。输入和工具都可读、但棋格外观客观歧义或 BoardIdentityCheck 无法确认时归 inconclusive/board_perception_unresolved;可靠投影为空候选归 inconclusive/no_legal_swap_observed。helper 崩溃、schema/hash/config 缺失、同输入输出不确定、validator 版本错或 interaction binding 漂移属于工具/契约损坏,归 tester_error/match3_solver_error | profile_contract_error。仅有通用 Actor 猜测而没有可靠 BoardProjection 与 pair 绑定时仍固定 inconclusive,不得靠重采样挑中一个幸运端点。专用模型调用计入现有单掷 ¥1.5 与 parent 链成本上限,禁止无界重试。
3.3.3 标准 Match-3 的视觉事务与输入锁
交换、消除、下落和补位不是装饰,而是玩家理解因果关系的标准玩法反馈。只要最终盘面与分数正确,不能证明这一手“可玩”:盘面若在同一同步调用里直接跳到终局,玩家无法判断哪两格交换、哪一组被消除、哪些棋子下落,也无法理解连锁来源。现有单张 post frame 只证明终点,无法识别这种时间维度假阳。
业务事务仍按本设计的可信输入边界在第二 tap 同步提交,动画不得延迟或补写 ctx.event。表现层新增独立受保护能力 match3VisualTimeline,与 match3ProducerProfile 的几何、选中环和感知 configHash 分离,避免动画演进改变已校准的棋盘身份。interaction registry 在同一 profile 下登记 visualTimelineCapability:{id,version,configHash},可信宿主暴露独立只读 probe;request、provenance、binding、runner 参数与宿主 preflight 五处逐字对账。producer capability 的 id/version/configHash 保持不变,动画能力缺失、错版、错配或被页面猴补都在创建 Actor 和成本预留前 fail-closed。
标准模板在第二 tap 同步结算时产生 Match3VisualTransaction/1。每枚现存棋子拥有稳定 pieceId 与游戏本地不透明 kindToken;交换只改变位置,消除删除对应 ID,重力按 ID 记录 from/to,顶部补位创建本 transaction 内从未出现的新 ID。事务固定包含 transactionId、moveId、规范 pair、交换前 8×8 piece 快照、交换后快照、每轮 {before,runs,matchedPieceIds,matchedCells,afterClear,gravityMoves,refills,afterFall}、最终快照、pendingTerminal、schemaVersion 和 transactionHash;每个 piece 固定为 {pieceId,kindToken},gravityMoves/refills 必须携带 pieceId 和 from/to。进入时间线前由受保护能力 deep-clone、校验并冻结,后续只能读取。kindToken 只供时间线调用主题绘制,不能包含主题名、颜色名或外部感知 classId。
runner 根据交换前 64 格的位置,把事务中的 kindToken 与初始 BoardProjection 匿名 classId 独立对齐,要求形成完整一一双射,并把映射及其 hash 封存在 Match3VisualAudit/1;映射不回传给游戏。随后 reference replay 复算交换、匹配去重、pieceId 守恒、清空、逐列压实、补位新 ID 和轮次衔接,并与同步事件的 moveId/runs/matchedCells、稳定终帧的新 BoardProjection 对账。同类棋子不能靠交换 pieceId 或伪造任意路径掩盖错误。游戏不能用一套好看的假快照给自己作证;事务原始字节/hash、视觉审计和 interaction audit 必须形成可回读闭包。时间线只消费事务,不改盘面、分数、步数、revision、事件或终局结果;idle 与首击仍只走 producer shell 和 canonical selection overlay。
有效交换的固定阶段为 swap → match_hold → clear → fall_refill → cascade_gap,每个连锁轮次依次重复 match_hold → clear → fall_refill → cascade_gap,最后进入 settle。无效交换固定为 swap_forward → rollback → settle。第一版时长为:交换 200ms、匹配停留 120ms、消失 180ms、下落与补位 240ms、连锁间隔 100ms、最终稳定 100ms;无效交换前移与回退各 180ms。单轮有效交换约 940ms,后续每轮增加 640ms。视觉完整门最多接受七轮连锁且总长不超过 5 秒;第八轮及以上、时间线超时或任何阶段被截断都明确不能 accept,并留下结构化诊断。
渲染必须读取时间线的当前视觉快照,不能读取已经完成全部补位的业务终盘再叠加“消除格闪白”。交换阶段让两个原棋子沿格心连线移动;匹配停留保持交换后盘面并明确标出将消除的棋子;消除阶段在原棋子上做缩放和透明度过渡;下落阶段按来源与目标格插值,顶部补位从棋盘上方进入;连锁必须一轮一轮播放,不能只保存第一轮匹配与最后一轮下落。终局画面延迟到 settle 完成后显示,业务结果可以提前封存但不能抢走最后一次消除过程。
专项标准的消除阶段不能只让棋子缩小或透明消失。每个真实 matched cell 必须同时出现局部消除特效:格心先产生短促亮核,随后出现一圈向外扩散并衰减的轮廓,以及若干沿不同方向离开的短寿命碎片;颜色跟随被消除棋子的主题色,位置与 pieceId、matched cell 和当前连锁轮次绑定。特效只围绕真实消除格发生,不得在未命中格伪造反馈,也不得用全屏闪白、整盘蒙层或大面积震动替代。三连保持克制,多格或后续连锁可以适度增强数量与尺度,但必须保留棋子主体和受影响列的可读性,不能遮住下落、补位或下一轮匹配。
局部特效属于 match3VisualTimeline 的标准表现能力,不由每款生成游戏自行维护另一套粒子生命周期。visual timeline capability 的 configHash 只覆盖平台固定代码、阶段时长与效果参数,继续在 Writer 前与 registry、request、provenance、binding 和 host probe 五方对账;产物主题色不得混入这条 pre-Writer identity。可信 builder 在 Writer 收口后、build 前读取唯一 Match3EffectPalette/1 构建清单,校验后连同 producer 的冻结 geometry snapshot 一次性装配给 L1 时间线实例。Palette 的精确形态为 {schemaVersion:'Match3EffectPalette/1',entries:[{kindToken:<JSON原语>,color:'#RRGGBB'}]};entries 按 kindToken 的 canonical JSON 排序,禁止透明色、重复 kindToken、逐帧回调和动态 CSS。paletteHash=SHA256('match3-effect-palette/1\n'+canonicalJson(palette)),与 geometryHash、artifactHash、build manifest、host probe 和 EffectAudit 绑定,但不改写平台 capability configHash。L3 游戏不能提交格心、逐帧改色或决定特效位置。
时间线的 view() 增加只读 effects,每项固定为 Match3EffectView/1:{effectId,transactionId,cascadeIndex,pieceId,cell,kindToken,progress,core,ring,shards}。effectId=SHA256('match3-effect-id/1\n'+transactionHash+'\n'+cascadeIndex+'\n'+pieceId);core 为 {radiusPx,alpha},ring 为 {radiusPx,lineWidthPx,alpha},shards 恰为八项 {shardIndex,angleRad,distancePx,sizePx,alpha}。第 i 枚碎片的角度由 SHA256('match3-effect-shard/1\n'+effectId+'\n'+i) 前四字节按大端无符号整数除以 2^32 后映射到 [0,2π);所有数值在 hash 前按 canonical JSON 的有限数字规则编码。
唯一绘制入口为无业务回调的 renderEffects(mainContext)。L3 不调用它;可信 host 在游戏主体 render 完成并恢复 Canvas 状态后,以固定逻辑像素 transform 在主画布最后合成一次。host 先恢复游戏可能遗留的 clip、globalAlpha、composite、filter、shadow 与 transform,再由 renderer 自己 save/restore,固定 source-over、alpha=1、filter=none、无 shadow,确保 receipt 不能在不可见状态下成立,游戏也没有后续不透明绘制覆盖它。入口只接受插件 init 时取得的可信主画布 context,根据当前 effect view 绘制并返回冻结的 Match3EffectRenderReceipt/1:{schemaVersion,renderSeq,transactionId,cascadeIndex,effectViewHash,effectIds,coreCount,ringCount,shardCount,mainContextIdentity};每个真实渲染帧恰好调用一次,非 clear 时 receipt 的 effectIds 与 primitive count 全空。effect generator 是 sealed transaction 的纯投影,不得调用 ctx.event、回调游戏或改变盘面;只在 clear 阶段非空,进入 fall_refill 前原子清空,reset、dispose 和 restart 不得残留。
标准参数固定为:每个 matched cell 一个亮核、一圈扩散环和八枚碎片;亮核从 3px 扩至 8px,扩散环从 8px 扩至 18px、线宽不得低于 1.5px,碎片从格心外移至少 12px,80ms 时尺寸不得低于 2px。亮核在 clear 后 20–80ms 可见,环和碎片在 40–150ms 可见;80ms 时三类 primitive 的 alpha 均不得低于 0.35。三连保持上述基线,多格或后续连锁只能按固定 config 增强,不接受游戏层自由放大。通用 particles-juice、飘字、全屏闪白和棋子本体透明度均不计入这一标准;即使它们出现在 matched cell,也不能替代 effect view 和可信 renderer receipt。
效果审计单独形成 Match3EffectAudit/1,单向引用 Match3VisualTransaction/1,并绑定 visual capability/configHash、artifactHash/build manifest、geometryHash、paletteHash、每轮 effectIds、相对 clear 起点的 effect view hash、render receipt 和由固定 primitive 独立栅格化得到的 per-frame effectMaskHash。Match3VisualAudit/1 同样只引用 transaction,不反向引用 EffectAudit;Match3RollInteractionAudit/2 直接绑定 VisualAudit 与 EffectAudit 两者的 ref/hash 并执行 matched cells、轮次、稳定终盘的交叉一致性,SingleRollProof/3 再单向引用 InteractionAudit/2,引用图中不存在互引或循环哈希。能力缺失、只画本体透明度、未由 host 调用可信主画布入口、receipt 与 effect view 不一致、效果位置与 matched cells 不一致,或用通用粒子伪造局部像素,都不能形成 Match-3 专项通过证据。
第二 tap 被接受后立即锁定棋盘输入,直到 settle 完成。锁定期间的额外 tap 不得改变 selected、盘面、分数、步数、revision、事件序列、pendingTerminal 或 transactionId,也不得启动第二条时间线。首击选中态继续遵守只有 canonical 白环变化的现有约束;时间线完成后的下一帧恢复输入。动画可以触发音效、粒子和轻量震动,但它们只能辅助时间线,不能替代棋盘主体运动。输入锁不向正式 Actor 动作账插入第三个 action;专项门另起同 artifact、同 seed 的零模型 InputLockProbe/1,对照 control 在动画 300ms 注入受信第三 tap,核验上述业务状态与时间线身份逐字不变。
第二 tap 的正式 action 仍按现有规则总计推进 600ms,并保留 action-2 post frame 作为同步事务因果帧。此后 runner 在创建下一份 ActorView 或调用 Judge 前启动自己的 visualDrain:它没有 Actor selection、actionId 或 proof 资格,每 120ms 推进受控虚拟时间并明确禁止任何新的 ctx.event,直到 settle 或 5 秒上限。visualDrain 与每轮 clear 的相对采样共同产生独立的 visualSettlementFrameRef、Match3VisualAudit/1 和 Match3EffectAudit/1,进入 specialty gate 与 finalPostguard,但不得冒充 action-2 post frame或满足业务 proof obligation。
证据闭包 contract-first 升级为 Match3RollInteractionAudit/2 与 SingleRollProof/3。InteractionAudit/2 引用并绑定 Match3VisualTransaction/1、Match3VisualAudit/1、Match3EffectAudit/1、InputLockProbe/1、filmstrip manifest 和 visualSettlementFrame 的 ref/hash;SingleRollProof/3 引用 InteractionAudit/2 的 ref/hash,并继续保留现有业务 proof package。顶层 playtest/3 形态不变,仍通过 proofPackageRef/hash 进入内部包。旧 Match3RollInteractionAudit/1 与 SingleRollProof/2 冻结只读、不得静默加字段或适配升级;缺任一视觉 sidecar、ref/hash 不闭合或旧版包声称视觉完整都 fail-closed。
filmstrip 从第二 tap 派发时开始采样,固定保留 0、80、160、240、360、500、600ms 的业务时间轴;每个 clear 阶段再按自身起点增加 +20/+80/+150ms 三个相对采样,此后由 visualDrain 每 120ms 采一帧。版本化 Match3FilmstripAnalyzer/1 固定棋盘 ROI、棋子主体 mask、局部特效 mask、轨迹与 alpha/scale 阈值,并以 configHash 绑定;HUD、飘字和屏幕震动不得计入主体 distinct frame,局部特效也不得拿来冒充棋子运动。只有观察完同步事件声明的全部轮次、超过按轮次数复算的理论最短结束时间、且连续两帧间隔至少 120ms 的主体盘面稳定,才能判定 settle,不能在 match_hold 或 cascade_gap 提前停止。
机械门必须同时满足:棋盘主体至少出现三个 distinct frame;有效交换中交换对先发生位移,随后 matched cell 的主体 alpha/scale 变化;每个 effectId 在相对采样中依次出现亮核、扩散环和八枚碎片,core/ring 各自独立栅格面积至少 24/32px,碎片合计至少 40px,主题色与采样前同位置背景的 WCAG 相对亮度差至少 0.18;ring 半径从 +20ms 到 +150ms 至少增加 7px,碎片质心同期至少外移 10px,+80ms 的三类 primitive alpha 均不低于 0.35。effect primitive 的归属、render receipt 和独立栅格化 mask 三方一致;合成截图在排除棋子本体 8px 核心区后,对预期 ring+shard mask 的像素变化召回率至少 0.60,不能只凭某个 ROI 有像素判绿。之后再发生受影响列的位移;每个 puzzle.match-formed 对应一个独立的消除、特效和下落轮次;稳定终帧与同步业务终盘一致;独立 InputLockProbe 通过。相邻 matched cell 的效果允许视觉重叠,但审计按 effectId 的 primitive sidecar 分开归属。无效交换的 effect view、receipt effectIds 与 effect mask 必须全空,并看到前移、回退、稳定三段,最终盘面与交换前等价且成功事件为零。
时间线自身报告的 phase 只作诊断,不能单独满足验收。runner 必须以真实截图的棋盘主体变化、可复算事务和事件轮次交叉验证,防止游戏伪造 phase 或“有计时器、没运动”的假动画。能力 probe、捕获器或 analyzer 崩溃归 tester_error;游戏未启动时间线、事务重放不一致、瞬移、缺阶段、输入锁破坏、超时或截断归 verified reject;粒子遮挡、压缩或渲染异常使主体运动客观无法判定时归 inconclusive/visual_motion_unresolved。机器门只能证明阶段存在、顺序、持续时间范围、输入锁和稳定终点;缓动是否自然、动作是否看得清、粒子是否遮挡主体、音画是否同步、真机是否掉帧,仍由真人真浏览器验收。每款至少真玩五次有效交换、三次无效交换和一次连锁,并保留 filmstrip 或视频证据。
3.3.4 标准 Match-3 的音乐、节奏音效与静音
“装了音频插件”不等于有音频体验。2026-07-18 的五款复核确认:五份 L1 都注册了 audioMusic,但 L3 没有载入曲谱、没有在首次用户手势后启动循环,也没有把声音接到视觉时间线;现有 blip/thud/chime 只有三份固定 PCM,多个语义别名仍落到同一个样本。Gem 在同步连锁递归中逐轮调用 chime 会让声音在动画开始前同时叠起,Candy、Fruit 则整次连锁只播一次,Porcelain、Rune 甚至没有标准消除音。这类结果即使 playSfx() 被调用、source.start() 成功或 probe.hasSong=true,也不能成为内容金标的音频证据。
标准 Match-3 新增受保护能力 match3AudioDirector,并且整款只能有一张实际发声的音频图。导演独占 BGM、玩法 SFX、终局音、master 与静音状态;标准 Match-3 下 audioMusic 可以继续由注册器做无节点生命周期检查,但不得进入 L3 插件门面,也不得创建第二组 source/gain。五款 L3 中现有的 playSfx() 全部退出。v1 不播放菜单、首击选中和重玩 cue;胜负只由带 terminalKind 的最终 settle transition 触发。reset 只清事务 cue,restart 不重建 BGM,dispose 必须停止全部 source、断开全部节点并清掉监听。导演与 match3VisualTimeline 消费同一份冻结视觉事务,L3 看不到调度、渲染或总线入口。
视觉时间线不能只暴露“当前 phase”。它新增 host-only 的单调 Match3VisualTransition/1 账,每项固定为 {transitionSeq,transactionId,transactionHash,phase,cascadeIndex,transitionVirtualTimeMs,terminalKind};terminalKind 只允许 null|'win'|'lose',时间线在 begin 时把五款历史 win/won/lose/lost 归一,拒绝其它非空值。begin() 记录首阶段,update(dt) 即使一次跨过多个阶段也逐条记录所有进入点,reset/dispose 后旧事务不可重放。导演按 transitionSeq 恰好消费一次,不能轮询终态或按业务递归播放声音。每批调度以消费时的 {virtualNowMs,audioNow} 建立临时映射并生成 epochId,保留同批各 transition 的虚拟时间差;真实听感验收使用实时 RAF 推进,离线和 600ms 跳步只验证顺序与确定性调度,不把两个未经校准的时钟直接相减。
页面 boot 后可以用普通 fetch 预取 BGM 字节并核对 hash,但不得创建 AudioContext、decode 或发声。host 只有在 Event.isTrusted=true 且浏览器 user activation 有效的原生 pointerdown/keydown 中才尝试创建/恢复唯一上下文;公开 host.tap()/do()、直接 _emit、模型观察和脚本事件没有启音权。玩法输入仍在同一原生调用栈同步派发,不等待异步 resume/decode。BGM 在预取完成且 context running 后 decode,buffer ready 后 500ms 内淡入;未 ready 时不阻塞玩法,也不另造首次启音 cue。恢复失败可由后续可信手势重试,且每次失败只留一条结构化原因。
每款由固定 L1 注入唯一、深冻结的 Match3AudioTheme/1,精确形态为 {schemaVersion:'Match3AudioTheme/1',themeId,bgm:{url,sha256,bpm,beatsPerBar,loopStartMs,loopEndMs,gainDb},cue:{rootHz,scaleSemitones,toneWaveform,accentWaveform,sfxGainDb,tailMs},control:{defaultMuted}},禁止额外键。themeId 只允许 [a-z0-9-]{1,32};sha256 为 64 位小写十六进制;bpm 为 80–120 的有限数;beatsPerBar 只允许 3 或 4;0<=loopStartMs<loopEndMs<=decodedDurationMs;gainDb 为 -24..-6;rootHz 为 110..880。scaleSemitones 必须是升序、无重复、落在 0–11 的非空整数数组;两个 waveform 只能取 sine|triangle|square|sawtooth,sfxGainDb 只能为 -12..-1,tailMs 为 200..450,全部数值必须有限。swap、rollback、clear 三层包络、fall、settle 和终局短句的时长、频率倍率与最大并发写死在导演平台 config 中并进入 capability configHash,主题只能在上述受限范围内选调式与音色,不能注入回调或任意 oscillator 参数。themeHash=SHA256('match3-audio-theme/1\n'+canonicalJson(theme)),与 artifact、build manifest、原始 BGM hash、probe 和 AudioAudit 绑定;偏好键只由 host 派生,不进入 theme。
v1 只有一层 BGM,不承诺运行期双轨或强度重混;节奏变化来自与视觉阶段同步的玩法 cue。BGM 使用无歌词、无第三方采样版权依赖的主题器乐,源文件与生成元数据入仓;每款构建只携带本款一首 18–32 秒循环,44.1kHz、双声道 MP3、码率不高于 96kbps、文件不超过 512KiB、解码后 PCM 不超过 12MiB,活动 source 不超过 16、Web Audio node 不超过 64。url 只允许 ./assets/audio/<安全文件名>.mp3,拒绝绝对 URL、..、query、fragment、重定向、非 audio/mpeg、超 512KiB 和响应长度不符;host-owned package asset loader 先按原始字节验 SHA-256,再把 {bytes,rawHash} 交给导演 decode,插件不得直接取得 fetch/crypto。原始 MP3 的 44.1kHz 由资产门校验;decodeAudioData 会重采样到当前 AudioContext.sampleRate,运行时只能核对解码结果与上下文采样率一致,不能再要求解码后的 AudioBuffer 仍为 44.1kHz。hash 不符、解码失败或时长越界都不播放并留下原因;本地 stage 的 BGM fetch+hash+decode P75 目标不超过 800ms,但不作为低端网络承诺。
五款主题不是只看 hash。固定听感锚如下,自动侧另取 BPM、onset 密度、频谱质心和离线 PCM 距离,人工侧做隐藏名称的五选辨识;只改一字节、音量或整体移调不得算不同主题。
| 主题 | 节奏与调式 | 主要配器 | 禁止退化 |
|---|---|---|---|
| gem | 104 BPM、C 小调 | 玻璃槌音、柔和合成脉冲、轻电子鼓 | 刺耳高频铃声、持续环境铺底 |
| candy | 112 BPM、F 大调 | 木琴、弹拨音、轻手拍节奏 | 幼儿儿歌感、尖锐玩具音 |
| porcelain | 88 BPM、D 五声音阶 | 清淡拨弦、竹木打击、空气感垫底 | 厚重电影鼓、泛化古风采样拼贴 |
| fruit | 108 BPM、G 大调 | 木质马林巴、原声拨弦、手鼓 | 卡通挤压声、过密打击 |
| rune | 96 BPM、D 小调 | 低沉合成器、框鼓、克制金属泛音 | 恐怖长鸣、遮蔽操作音的低频轰鸣 |
导演的唯一节点拓扑为 BGM source → bgmGain → masterGain 与 SFX source → sfxGain → masterGain 两路汇合,再严格经过 masterGain → limiter → auditTap → destination。不得存在绕过 masterGain、limiter 或 auditTap 的 destination 连接。BGM 循环边界使用产物写死的 loopStart/loopEnd;SFX 只使用短寿命 source。BGM 默认比动作音低 8–14dB,任何单次动作不得靠无限叠加增大响度。标准动作节奏固定为:swap/swap_forward 进入时播放 80–140ms 的横向移动音;rollback 进入时播放与有效交换具有不同 PCM 指纹的低沉回退音;每轮 clear 进入时播放一次复合消除音;fall_refill 进入时按整轮聚合播放一次落定音;最终 settle 只在有终局时播放胜负短句。禁止为每颗棋子各播一次落定音,也禁止把业务同步递归中的全部连锁音提前堆到同一时刻。
普通消除音至少由三层构成:30ms 内的清脆起音、120–220ms 的主题音色主体、200–450ms 的短尾音。三层共用当前主题的调式和音色,但必须拥有不同包络;单个旧 chime、只提高音量或重复播放同一 PCM 都不合格。第 cascadeIndex 轮在前一轮基础上每轮升高两个半音,第四轮后封顶,并轻微增加尾音能量;每轮 clear 只起一次,起音与视觉 clear 切换的虚拟时间误差不超过 50ms。有效交换、无效回滚、普通消除、连锁消除和落定至少形成四种不同的 PCM 指纹与音高走向。
BGM 必须具有可听节拍而非持续长音或两秒蜂鸣。buffer ready 后 500ms 内淡入;循环三次的接缝静默不得超过 100ms,边界前后波形跳变不得形成可听 click,不得爆音或重复叠播。v1 不提供常态/紧张双混音,也不接受只修改 intensity 探针冒充音乐变化;强度分轨在完整信号来源、迟滞和小节对齐协议完成前不进入本专项验收口径。
宿主在可见画布容器上方提供固定的 DOM 扬声器按钮,而不是把无语义图形画进 canvas。按钮使用熟悉图标、aria-label/aria-pressed、44px 最小点击区,支持焦点、Enter 和 Space,避开 safe-area;pointerdown/click/keydown 在玩法桥之前 stop propagation,输入桥同时按 composedPath 排除 host control,点击不得落入棋盘或产生业务事件。偏好由 host-owned adapter 按 huijing.match3.audio.<themeId> 命名空间读写;存储不可用或坏值退默认且只记一次,插件不直接取得 localStorage。静音只 ramp 唯一 master gain,不 stop/recreate BGM;100ms 内 limiter 后输出归零,取消后 500ms 内只恢复原有的一份 BGM。页面 hidden 时平滑降到零,visible 后按用户偏好恢复,context interrupted/suspended 时等待下一次可信手势。host 的固定 destroy() 必须 abort 未完成资产请求、停止 source、断开节点、移除按钮和页面监听、执行 registry.disposeAll 并关闭 context,studio 重开不得叠播。
可信 host 暴露只读 Match3AudioProbe/1,至少包含 themeHash、contextState、unlockState、bgmLoadState、bgmRawFileHash、bgmSourcesCreatedTotal、activeBgmSourceIds、graphGeneration、muted、节点/source 数、三条总线当前增益,以及按顺序冻结的 cue receipts。每个 transition 驱动的 Match3AudioCueReceipt/1 固定记录 {cueSeq,transitionSeq,transactionId,phase,cascadeIndex,cueKind,epochId,transitionVirtualTimeMs,scheduledAudioTime,startCallAudioTime,lateByMs,layerCount,pitchSemitones,cueSemanticHash};cueSemanticHash 只绑定主题、音高、层数与包络参数,不能称为 PCM 证据。真实 offlinePcmHash 只能由锁版离线渲染器另行生成并进入 AudioAudit;v1 不存在非事务 cue receipt。bgmRawFileHash 只指原始文件字节;跨浏览器 decode 后 PCM 不要求逐字相同。正常、静音、恢复和 hidden/visible 后 activeBgmSourceIds 必须始终恰为一项,destroy 后为零;graphGeneration 在单次 host 生命周期内不变。probe 只作诊断,不得独立完成专项通过或内容金标签认。
专项阶段同步生成 Match3AudioAudit/1。BGM 与 SFX 可在各自 gain 后设诊断 analyser,正式 master 测量固定在 limiter 后的 auditTap。真实 RAF 每帧从 fftSize=2048 的 analyser 读取一次时域窗,按 audio currentTime 留 RMS/peak;onset 固定为相对前一秒底噪提高至少 12dB 且高于 -45dBFS、连续两帧成立的首帧,允许误差按 34ms 窗口上取整。审计按实际输出窗口保存 source/node 身份、采样窗起止、RMS、peak、analyserOnsetAudioTime,并引用 transition 与 cue receipt。静音只认 auditTap 窗口归零,不能读取源 buffer 或 master 前数据自证。实时 analyser 不自报精确削波样本数,只核对容差 RMS/peak/onset;clippedSampleCount、确定性 cue PCM hash和峰值硬闸只来自锁版 OfflineAudioContext。探针和审计不得读取麦克风、系统输出或用户设备信息。
自动验收分三层。纯逻辑层使用 sealed 视觉事务验证主题 schema/hash、transition 不漏不重、连锁升调、静音状态机和错误降级;离线音频层使用 Match3AudioAnalyzer/2。v1 曾把完整正频谱的 flatness 下限固定为 0.05,但仓内八首真实 BGM 有五首被误杀,并且给窄频音乐叠加约 -60dBFS 白噪声即可越线,证明该指标奖励噪声底而不是编配质量。v2 因此只保留 flatness 不高于 0.75 的白噪声拒绝门;低 flatness、80–12000Hz 对数频带占用、谱带宽和五主题距离全部只作 shadow 诊断,在取得 30–50 首人工标注语料前不得阻塞发布。可靠硬门仍要求 BGM 估计 BPM 与声明值误差不超过 4、节拍置信度不低于 0.55、onset 密度为每秒 1.5–8、频谱质心为 250–5000Hz、连续十秒至少 85% 的 100ms 窗口高于 -55dBFS、三循环接缝静默不超过 100ms且波形跳变不超过 0.2;limiter 前峰值不得高于 -1dBFS,离线削波为零,limiter gain reduction 超过 3dB 的窗口不得超过 1%。每个主题的 swap、rollback、四档 clear、fall、胜利和失败共九种 cue 都必须经真实 Chromium OfflineAudioContext 渲染,保留 limiter 前后 PCM、真实 reduction 采样和稳定 offlinePcmHash。
真实 Chromium 层使用固定 seed 与动作路径,在首次可信手势前后核对 无 context/无输出 → running/BGM非零,分别真实触发有效交换、无效交换、多轮连锁、胜利和自然耗尽失败,核对 cue 数量、顺序、transaction/transition 绑定、limiter 后非零输出,以及静音归零、恢复非零且 BGM source 不重建。随机盘未实际出现指定场景时必须换 sealed seed 重跑,不能用普通交换、状态注入或函数调用替代。机器证据仍不能证明音乐好听、消除音有满足感或五款主题足够不同;每款必须由真人在真实浏览器有声试玩至少两分钟,完成有声、静音、恢复、有效、无效、连锁、胜负终局和重玩,才算完成 harness_fixture 的人工听感复核;盲听者每人至少识别 4/5,五款合计不得有无人识别的主题。该复核只校准专项门,不签内容金标。
实现顺序保持最小闭环:先给视觉时间线增加 host-only transition 账,再新增导演、主题契约、probe/receipt、专项 Match3AudioAudit/1 与宿主 asset/preference/启音/静音桥;导演作为独立 L1 capability 进入 registerOrder 取得受控 context,但不进入 L3 plugins。标准 Match-3 的 L3 门面同时移除 audioMusic 与导演,删除五份 L3 全部 playSfx(),模板和五款各只装一份导演与一首主题 BGM;最后补单元、离线音频、真实 Chromium 和人工听感证据。InteractionAudit/2 对 AudioAudit 的正式绑定和三批基线仍是后续门,专项样本通过不能翻转 canonicalRuntimeEligible=false。
截至 2026-07-20,Match3AudioAudit/1 已按本节设计补全。auditId 绑定主题、导演配置、host 核验后的 BGM 原始字节、插件版本和 auditTap;顶层另存 BGM 原始字节与 runtime 节点绑定、滚动窗口游标、淘汰数和未决 onset。每个 limiter 后窗口都保留真实采样起止、FFT 与采样率、RMS/peak、动态底噪、12dB onset 阈值、source/node/auditTap 身份、视觉 transition、cue receipt 和逐 cue detected/missed 终态。滚动淘汰保持 receipt 与 onset check 的引用闭包,未决队列或容量异常 fail-closed;读口幂等,读取本身不追加样本。旧版只有 frame、时间和 RMS/peak 的部分账已经退出现行口径。
音量问题的根因不是“有无 source.start()”,而是原混音没有按真实 PCM 约束 BGM 与 cue 的层级,分层归一后动作起音被 BGM 和动态底噪遮蔽;校准前固定场景只有 18/214 个 cue 被实时 onset 门检测。修复把导演 layerGain 调到 0.6、五主题 sfxGainDb 统一为 -2dB,并按主题把 BGM 调到 -15、-18.5 或 -18.9dB。版本化 Match3AudioMixBalance/1 对五主题九类 cue 共 45 项逐项保存独立配方峰值差,45/45 落在 9.22–13.99dB,Match3AudioAnalyzer/2 仍为 overallPass=true、failures=[],原有 BPM、能量、频谱、接缝、削波与 limiter 门没有放宽。这个 8–14dB 门比较的是 BGM 与 cue 各自独立渲染后的配方峰值,不等于两者同时进入共享 limiter 后的实际可辨识度;combined BGM+cue 测量仍是 P1,不能拿当前数字替代。
最终固定 Chrome 证据中,有效消除和无效回滚各 5/5,多轮连锁胜利与自然耗尽失败合计 10/10;266/266 个应发声 transition 都有唯一且 layerCount>0 的 receipt,10/10 终局 onset detected,110/110 个事务至少有一个动作 onset detected。事务 onset 的正式场景门为不低于 90%,逐事务结果仍完整保存;transition 到 receipt 与终局 onset 保持 100% 硬门。harness 的静音/恢复采样、独立 Chromium 进程组、可中止 BGM 预取、bundle 与 runtime module hash 对账也继续生效,因此上述数字只对应当前已绑定制品和固定场景。
生产 runner 只通过 host verifier 安装的不可替换 trusted bridge 读取 AudioAudit,不接受页面自挂 __genHost。每个 completed Match-3 action group 后立即进入无输入 drain,以 120ms 受控量子推进到 settle 与 onset 全部终结;期间新增业务事件即失败,并在该 group 的独立目录封存只含当前事务的 sidecar 原始字节和 SHA-256,旧目录或旧 formal 文件不得复用。Match3RollInteractionAudit/2 与 SingleRollProof/3 的 schema、目录校验和构造函数虽已具备,当前 runner 仍禁止签发,视觉、特效、输入锁等全部 sidecar 尚未在同一真实 run 闭合。每款至少两分钟的真人有声试玩、重玩体验与 4/5 盲听也未执行;在这些 fixture 人工证据、Audit/2 与 Proof/3、完整总门、fresh 25、historical 11 和 production shadow 20 收口前,不能把音频专项样本升级为内容金标、宣称可放量或翻转 canonicalRuntimeEligible=false。
production-style 的真实 Gem 单轮校准也已跑通专项路径:Actor 首次选择成功,以两次动作产生三条业务事件,specialty gate 通过,耗时 68.09 秒、费用 ¥0.11172。本地校准目录中的 match3-audio-audit.json 经正式契约校验通过,原始字节 SHA-256 为 e5a7fe5dd83a66d12b490a85955a8b3470ec27b2ac4581242f90f14d64f53a24,共 81 个窗口、3/3 cue onset detected、pending=0;该目录按证据保留策略不进入仓库,因此这里记录事实与 hash,不把它声明为仓内长期证据链接。该轮 Judge 因其它默认 proof 缺失而返回 inconclusive/proof_missing,不否定这份专项 sidecar,也不能提升为整掷通过;runner 仍不签 Audit/2 与 Proof/3。
3.4 600ms 虚拟时间
页面完成 boot 后进入受控时钟。截图、M3 推理、非法动作重试和 Judge 调用期间,游戏逻辑时间全部冻结。合法 tap、key 或 drag 派发后精确推进 600ms;wait 接受 100–3000ms 并推进请求值。每次推进必须等待 CDP virtualTimeBudgetExpired 后,才能读取 post frame 和 post event seq;未等到预算完成属于 tester_error/environment_error。
600ms 是统一的人类操作节拍,不等于把所有游戏改成回合制。动画和计时器仍按原有时间比例推进,只是外部模型延迟不进入游戏时间。节奏类玩法由 Actor 主动 wait 到目标窗口再操作;顾客耐心、倒计时和敌人行动只在量子推进时消耗。runner 同时保留墙钟时间,用于成本和基础设施超时,但墙钟不得参与玩法成败。
合法但无效的点击会正常推进 600ms 并记录“无业务事件”;只有协议非法动作才冻结帧。每个 action 的因果账固定为 preFrameHash/preEventSeq → dispatch receipt → virtual-time budget → postFrameHash/postEventSeq,动作证据只取 (preEventSeq, postEventSeq],禁止把 LLM 等待期、动作前日志或下一动作日志混挂。这样既不替 Actor 掩盖真实失手,也不让格式错误烧掉游戏窗口。
标准 Match-3 的 visualDrain 是唯一的诊断性续时例外:它只能发生在第二 tap 的 600ms action 量子完成之后、下一份 ActorView 和 Judge 之前,没有 actionId、不得接收输入、不得产生业务事件,也不得进入 proof step。它只为 Match3VisualAudit/1 采集 600ms 后的动画尾段和稳定终帧;任一新 ctx.event、业务状态变化或超时都使视觉审计失败。普通 gameplay wait 仍须由 Actor 显式选择,不能借 visualDrain 偷跑计时玩法。
输入因果不使用“点击后 600ms 内都算本次点击”的宽时间窗。CDP 在派发前把 actionId 绑定到一个浏览器原生 isTrusted Event 身份;每类 capture listener 用自身闭包里的固定 listenerType 对账,不读取可被页面改写的 event.type。原生 isTrusted getter、String、RegExp.test 与受控 RAF 使用的 Map 方法和 size getter都在页面脚本前捕获。宿主只在处理该 Event 并同步分发 inputBridge 的调用栈内向 ctx.event 暴露归因。Promise、timer、RAF、保存事件二次派发、直接 _emit 和公开 host.stepFrames()/tap()/do()/state() 都没有输入归因;即使页面在真实 pointerdown 回调里嵌套调用这些会同步进入游戏代码的公开 host 面,宿主也会临时清空归因,返回外层 handler 后才恢复原 action。这样阻断页面用公开驱动 API 冒充真实输入,同时保留同一原生 handler 的同步前后事件。
这条边界同时约束生产者时序。选择、移动、攻击、选配方、交付和工序完成等直接输入结果必须在 handleTap/handleKey 同步栈调用 ctx.event。翻层、下一关、订单出现和结算等时间结果必须由注册表明确允许 wait,并在显式 wait 的受控推进中产生。延迟若落在 0 < delay <= 600ms,事件会发生在上一输入动作的量子内但没有输入归因,不能成为 proof;禁止用恢复宽窗口掩盖,生产者应改为同步提交输入结果,或把真正的时间里程碑安排在 600ms 之后。五个官方模板固定层均让 pointerdown 同步直达 handleTap;解谜过关停顿、TRPG 翻层、经营首单分别为 700ms、700ms、800ms,非遗首道就绪为 700ms,均晚于输入量子,可由下一次显式 wait 观察。
3.5 品类 proof obligation
硬证只回答 brief 与 proof profile 中要求的闭环是否发生。每个核心子义务必须原子编号;单步义务至少引用一个动作、一个动作后画面和一个 scope=game 的业务事件,多步义务的每个 step 都独立满足三证。p:*、诊断日志、音效、粒子、像素变化、分数增长或模型文字均不能单独满足义务。事件是可审计的游戏自报,不是单独真相,必须与 post screenshot 交叉核对。
| 品类 | 必需 proof obligation | 不足以证明 |
|---|---|---|
| narrative | 从可操作场景作出至少一次有后果的选择;到达明确结局;结局与已走分支一致 | 只翻一页、属性变化、看到“结局图鉴”入口 |
| trpg | 进入战斗;一次攻防结算真实改变遭遇或敌我状态;至少击杀并翻层;brief 只要求升级时证明等级真实增长,明确要求天赋选择时才证明选择并返回下一层 | 音效、粒子、骰子动画、遭遇状态未变的重复攻击 |
| heritage | 按模板声明的顺序完成全部工序且每步有可见判定;工序数不得少于 3;出现成品事件和成品评分 | 局部分数、反复回炉、只完成前三步、把一种手艺的固定工序名强加给其他手艺 |
| puzzle | 合法移动改变棋盘;最终棋盘满足目标;出现关卡完成事件和成绩;仅对已核验标准 Match-3 binding 追加一次真实有效交换 | move 计数增加、插件日志增长、模型口头宣称归位、solver 仅枚举出候选 pair |
| sim-business | 读取一份订单;按订单完成选择;成功交付;出现正营收或成功订单事件;结算与业务事件一致 | 顾客生成、超时离开、失败结算、零订单但 UI 齐全 |
品类义务来自 brief 与版本化注册表的交集。注册表有独立 schema、版本号、校验器和正负样本;brief 明确要求的升级、解锁、失败结算等关键能力必须按确定性规则提升为 required,注册表不能把 brief 没要求的长线内容强加给短局验收。Actor 和 Judge 都不能临时发明义务。若品类无法识别或义务无法确定,outcome=inconclusive,不能退回通用“有响应即通过”;注册表/schema/加载器自身损坏才归 tester_error。
brief 提升只处理用户需求文字;interaction 提升只处理可信交互身份。两条路径在注册表中分栏保存、分别解析,不能用“消除”“三连”“交换”等 brief 关键词猜测某个 puzzle 是否属于标准 Match-3。普通 puzzle.match-board 没有 interaction binding 时仍按原四项默认义务验收,不新增 Match-3 行为或事件要求。
3.5.1 业务事件生产者契约
2026-07-14 实施审计证明,仅有义务注册表还不够。五个官方模板的 27 个默认必需义务中,按当前 tag/message 规则只有 4 个能产生精确候选;历史 11 局的 73 个必需义务中只有 19 个能命中。同时,“开局”可被宽正则冒充“升级后返回”,首层“翻层”可冒充“击杀后翻层”,零订单零营收的结算可冒充“结算一致”。这同时制造必然假阴和确定性假阳,不能通过扩大正则修补。
runtime 把诊断日志与业务事件拆成两个入口。ctx.log(tag, ...args) 只用于人读诊断,新生产验收永不使用它满足义务;ctx.event(type, payload, message?) 是唯一业务事件入口,由 runtime 在可信边界内写入版本化 game-event/1 信封。生成 prompt 和五个官方模板必须对关键用户结果调用 ctx.event,禁止 runner 再从自然语言中猜数值或关系。
| 字段 | 约束 |
|---|---|
eventVersion |
固定 game-event/1 |
scope / namespace |
固定 game 与 game/<type>;插件日志不得冒充 |
type |
直接来自 ctx.event 第一参数,格式为 <genre>.<observable-result>,如 narrative.choice-committed、heritage.product-completed、sim-business.order-served;不用游戏私有变量名 |
message |
人读说明,不参与数值和先后关系判定 |
payload |
直接来自 ctx.event 第二参数的普通 JSON 对象;仅保存该事件的业务前态、后态、标识和结算数据 |
payloadCanonical |
runner 对 payload 执行 Node stableStringify 得到的原文;跨语言消费者解析后与 payload 做 JSON 语义等值校验,不得自行重序列化浮点 |
producer |
runtime 写入,玩法代码不得自报 |
seq / actionId / virtualTimeMs |
runner 写入,runtime 与玩法代码不得自报 |
payloadHash |
对 payloadCanonical 原始 UTF-8 字节计算 SHA-256;1e-7、1e-6 等格式差异不再由 Python 猜测 |
ctx.event 只接受注册表白名单中的 type、可 JSON 序列化的普通对象 payload 和可选文字。非法调用不抛错中断玩法,而是返回 false 并写入可被 runner 识别的 event-contract-error 诊断;该 run 归 tester_error/event_contract_error,不归因游戏玩法,也不触发 writer repair。合法调用返回 true。runtime 为旧诊断消费者保留单向 tag/msg 投影,但该投影不能反向成为新验收事实。新生产没有采到所需业务事件时归 inconclusive/proof_missing;只有 runtime 实际产出非法业务信封时才归 tester_error/event_contract_error,普通 ctx.log 诊断不会触发该错误。
历史 bundle 只允许在显式 historical_replay 模式下经 legacy-game-log/1 适配器重放。适配映射是版本化 allowlist,键固定为 proofProfileId + legacyTag + requiredPayloadPaths,值固定为 game-event/1 type;禁止读取 message、禁止正则和模糊 tag。适配器只 JSON 解析旧 ctx.log 文本末尾已序列化的对象,不得从文案推理业务值。转换事件必须带 sourceEventVersion=legacy-game-log/1、adapterVersion、原始消息 hash 和 evidenceMode=legacy-adapted。未知映射归 inconclusive。历史适配仅用于历史校准,始终 publishFrozen=true,并排除 fresh 25、production shadow 20 和全部生产成功率。
3.5.2 payload 谓词与有序关系证明
义务注册表升级为 proof-obligations/2。注册表不再只按粗粒度 genre 解析,而是按 proofProfileId 解析。该 id 只能由生成编排器在 Writer 启动前依据可信 template route 选定,并写入 Writer 只读的生成 request;可信 builder 在 Writer 完成后把同一 id 和 proofRegistryVersion 写入 Writer 工具不可写的 provenance manifest。Writer、生成模型、游戏代码、Actor、Judge 和 runner 均无选择或改写权。proofProfileId + proofRegistryVersion + taskBindingHash 必须同时进入 acceptanceRequestHash、provenance manifest hash 和最终证据包 hash;runner 交叉核对 request、manifest 与命令参数三者一致。taskBindingHash 由当前生成任务 traceId 做 SHA-256 得到,发布边界按当前任务重算,内容相同也不得跨任务复用证据。repair 全 parent 链固定沿用原 profile 与 taskBindingHash,任何变更归 tester_error/profile_contract_error。
proof profile 增加与 briefOptionalRules 并列的 interactionOptionalRules。每条规则只有四个字段,禁止额外字段:
| 字段 | 约束 |
|---|---|
id |
注册表内全局唯一的稳定规则 id |
interactionProfileId |
必须逐字引用 canonical interaction registry 中存在的 profile |
requireObligationIds |
非空、无重复,只能引用当前 proof profile 内 defaultRequired=false 的义务 |
description |
人读说明,不参与匹配 |
同一 proof profile 内,一个 interactionProfileId 只能出现一次;同一义务不能被两条 interaction 规则重复提升。交叉校验还必须证明 interaction profile 的 proofProfileId、genre 与 templateRoute 分别等于当前 proof profile 的 id、genre 与 templateRoute。puzzle.match-board 首条规则固定由 match3.orthogonal-swap-v1 提升 puzzle.match3-valid-swap;该义务自身仍为 optional,避免非 Match-3 puzzle 被误伤。
interaction 条件解析使用显式身份,不读取 brief。新签发的 acceptance-request/2 与 acceptance-provenance/2 都必须带唯一的嵌套 interactionBinding 字段,值只能是 JSON null 或完整 InteractionBinding/1;不再同时保存平铺三字段。普通 puzzle 写明 null,标准 Match-3 写完整对象。request 的 canonical acceptanceRequestHash 覆盖这个字段的原始 JSON 值,provenance 逐字镜像;repair 只能继承 parent 的完整对象或 null。Writer、生成模型、游戏代码、Actor 与 Judge 既不能选择 profile,也不能填充或覆盖 binding。
新 /2 运行只允许下列状态,未列出的组合全部在 Actor 启动前归 tester_error/profile_contract_error:
| 状态 | request / provenance | runner 输入 | binding 文件 | Resolution 与发布 |
|---|---|---|---|---|
absent |
两边 interactionBinding 都显式为 null |
binding path 与 interaction scalars 全部不传 | 不读取、不生成;内容为 JSON null 的文件同样非法 | 强制生成 ProofObligationResolution/1,status=absent、interactionRuleMatches=[];普通 /2 可继续验收 |
verified |
两边都是逐字段相同的完整 InteractionBinding/1 |
path 必须存在;profile/version/semantic hash/task hash 标量只能由已核验对象派生并再次核对 | 原始字节 hash 与解析后语义 binding hash 都必须复算通过 | 强制生成 sidecar,status=verified;仅精确命中规则时提升义务 |
| 非法混合 | 缺字段、单边 null、对象不同、传了 path 却未传完整对象、absent 仍传 path/scalar、verified 缺文件或任一 hash/版本漂移 | 不得派发 Actor | 不得用空文件、JSON null、旧文件或临时补造降级 | tester_error/profile_contract_error,没有可用 Resolution |
legacy /1 |
由旧 request/provenance validator 原样读取;没有 interactionBinding | 只走旧 runner 参数面 | 不读新 binding 文件 | 只读 SingleRollProof/1,没有 sidecar,固定 publishFrozen;不能进入 /2 Resolution、Match-3 enforce 或新 accept |
verified preflight 的四方是 request 对象、provenance 对象、独立 binding 文件解析结果和 runner 派生参数。前三者逐字段相同;runner 参数只能由已核验 request 对象派生,并与文件结果再次对账。validator 同时对 binding 文件原始字节计算 SHA-256,对解析对象按 InteractionBinding/1 canonical 域复算 interactionBindingHash,并核对 interaction profile 与 proof profile 的 id、genre、templateRoute。absent 不创建第四份身份:runner 不生成文件,不传 path/scalars,Resolution 用显式 absent 记录这项事实。任何版本不存在、hash 失败、四方漂移或把非标准 puzzle 强挂 Match-3 profile,都不能退成 optional、inconclusive 或 brief 提升。
现有 playtest/3 与 SingleRollFactV3 是 strict contract,只有 briefRuleMatches,不能把 interaction 结果塞进该字段,也不能在同一 schemaVersion 下静默新增顶层字段。新 /2 runner 另存 proof-obligation-resolution.json 作为 ProofObligationResolution/1 sidecar,并把内部单文件包升级为 SingleRollProof/2:packageType 固定为 SingleRollProof/2,并新增必需的 proofObligationResolutionRef 与 proofObligationResolutionHash。旧 packageType=SingleRollProof 固定解释为冻结的 SingleRollProof/1。runner 先封存 sidecar 原始字节,再把 ref/hash 写入 single-roll-proof.json,最后计算 singleRollProofHash。SingleRollFactV3.proofPackageRef/hash 和 playtest/3 的 roll 投影继续只指向相应内部包,因而无需改变两份 strict 顶层 contract,同时形成 sidecar bytes → sidecarHash → SingleRollProof/2 bytes → singleRollProofHash 的闭包。legacy /1 只能读取旧内部包,不得补 sidecar 或改写成 /2。
| 字段 | 约束 |
|---|---|
schemaVersion |
固定 ProofObligationResolution/1 |
proofProfileId / proofRegistryVersion / taskBindingHash / acceptanceRequestHash |
逐字镜像本 run 的可信 proof 身份 |
interactionBindingStatus |
只能是 absent 或 verified;request/provenance 显式 null 且 runner 无 path/scalars 时为 absent,完整四方核验通过时为 verified |
interactionBindingRef / interactionBindingFileHash / interactionBindingHash |
absent 时三个字段都为 null;verified 时分别保存文件引用、原始文件字节 SHA-256、解析对象的语义 binding hash |
briefRuleMatches |
按注册表顺序保存,必须逐字镜像现有 evidence 顶层字段 |
interactionRuleMatches |
字符串数组,按注册表顺序保存;absent 时固定空数组 |
requiredObligationIds |
字符串数组;注册表默认必需、brief 提升与 interaction 提升的去重并集,按 profile obligations 原顺序保存 |
resolutionHash |
对上述字段按 proof-obligation-resolution/1 canonical 域复算 |
目录级 validator 必须同时读取 request、provenance、proof registry、interaction registry、resolution sidecar、SingleRollProof 与 evidence;verified 时再读取 binding 文件,absent 时反而必须证明没有 path、文件和派生标量。它先复算 binding 文件原始字节 hash 与语义 interactionBindingHash,再对 sidecar 原始字节复算 proofObligationResolutionHash,随后复算 SingleRollProof/2 hash,最后重建 required 集并核对每个 proofObligations[].required。schema 单文件校验只证明各文件形状正确,不能代替这次跨文件核验。sidecar 缺失、两类 binding hash 混用、字节 hash 漂移、SingleRollProof ref/hash 漂移、required 集与 evidence 不一致或把 interaction rule 混入 briefRuleMatches,都归 tester_error/profile_contract_error。interaction 身份只经 SingleRollProof/2 → ProofObligationResolution/1 闭包进入证据;JudgePackage 不携带 sidecar,只携带已经核验过的 required 义务及候选步骤。
首批 profile 至少区分分支叙事、掷骰爬塔、有序工序制作、匹配盘面和配方履约,避免把数字滑块或某一种手艺的固定工序名强加给整个品类。可信 route 找不到唯一 profile,或 request/manifest/runner 三方值不一致,都表示配置或契约边界无法建立,统一归 tester_error/profile_contract_error,不得伪装成合法证据不足。
heritage.ordered-craft 不固定“选料/画线/凿卯/修整”或任何具体手艺名称。profile 要求事件链证明 3–12 道有序工序;每个 heritage.step-completed 事件携带 workId、stepId、1-based stepIndex、totalSteps 和非空 judgement。该 profile 使用受限 evidence.orderedSeries,不是固定三步 sequence,也不是任意表达式:
orderedSeries 字段 |
作用 |
|---|---|
seriesId / event / allowedActionTypes |
定义重复步骤的稳定 id、精确事件 type/predicate 与合法动作类型 |
groupByPath |
固定按 payload 的 workId 分组,禁止跨作品拼证据 |
indexPath / itemIdPath / totalPath / judgementPath |
固定读取 stepIndex、stepId、totalSteps 与 judgement |
minItems / maxItems |
固定 3 与 12,防空链和无界采集 |
summary |
精确声明后继 heritage.craft-completed 的 workId、totalSteps、orderedStepIds、allStepsCompleted 路径 |
terminal |
精确声明再后继 heritage.product-completed 的 workId、score、works 路径 |
runner 只在同一 workId 下满足以下全部条件时物化动态候选:所有 step 事件的 totalSteps 相同且在 3–12;事件数恰等于 totalSteps;stepIndex 恰为 1..N 且严格递增;stepId 唯一、judgement 非空;series item 的 allowedActionTypes 固定只含 tap/key/drag;每一道工序使用两两不同的 actionId,并由各自 action 唯一对应的 postFrameRef 取证,禁止一次点击批量冒充 N 步;summary 在最后一步之后,且 workId/totalSteps/orderedStepIds 与步骤序列逐项一致、allStepsCompleted=true;terminal 又在 summary 之后,workId 相同、score 为有限数、works>0。summary 与 terminal 可以和最后一道工序共用同一动作及 post frame。runner 将它确定性展开成 seriesId:1 ... seriesId:N / summary / terminal 的 sequenceRefs,finalPostguard 从原始事件重建并逐项复核。缺步骤且没有完成自报归 inconclusive/proof_missing;已自报完成但索引、数量、作品 id、动作独立性或汇总矛盾归 reject/business_event_contradiction。Judge 只核每步截图、成品画面和手艺语义,不替机械层补步骤。
trpg.dice-tower 把“等级增长”和“天赋选择”拆开。brief 只提升级、成长或 level 时提升 trpg.level-increased,事件必须带 upgradeId 与 level before/after;只有 brief 明确提到天赋、技能三选一或 talent 时,才同时提升 trpg.level-increased、trpg.talent-selected 与 trpg.returned-after-upgrade。返回闭环的有序序列固定为 level→talent→floor,三事件都携带 upgradeId,并用 sameValue:[{path:'/upgradeId', stepIds:['level','talent','next-floor']}] 由 runner/finalPostguard 机械核对;floor 步骤可由 wait 证明。自动升级不能冒充天赋选择,缺天赋要求的 brief 也不能被强加选择页。
每个义务的权威数据模型固定为 evidence.sequence[]。每一步包含唯一 stepId、人读标题、event:{type,predicates[]}、非空 allowedActionTypes 和 postScreenshotRequired:true。allowedActionTypes 只能取 tap / key / drag / wait:玩家直接操作步骤通常只允许前三者;翻层、下一关、订单出现、结算等由受控时间推进产生的可观察结果可以明确允许 wait。事件模式先用精确 type 限定事实类型,再用 JSON Pointer 上的声明式谓词核对 payload。标量谓词形状固定为 {path, op, value?},首版只允许 exists / equals / oneOf / gt / gte / lt / lte;前后态比较形状固定为 {op: changed|increased, beforePath, afterPath}。JSON Pointer 缺失即不匹配;数值操作遇到非数值即不匹配;坏 path、坏 op 或不合 schema 的注册表归 tester_error/registry_error。
需要防止跨周期拼接证据时,只允许受限 evidence.sameValue[],形状固定为 {path, stepIds}:runner 要求列出的每个 step 在同一路径上都有 JSON scalar 且逐字相等,finalPostguard 从原始事件重算。它不支持计算、脚本或不同路径映射。机械层仍不执行任意表达式,也不做跨事件金额汇总或分支语义推理;这些一致性由 Judge 对事件与截图核对。
单事件义务是只含一步的序列。“选择后抵达结局”“击杀后翻层”“升级后返回战斗”“交付后出现正营收和结算”等关系义务是同一 run 内的有序事件序列。runner 必须找到严格递增的 event seq,每一步都必须归属其 allowedActionTypes 允许的合法动作并有自己的动作后截图。wait 只能证明“时间推进后观察到的业务结果”,不能冒充玩家输入反馈;firstPlay.firstFeedback 和“输入有效”仍只接受 tap/key/drag 的因果事件。跨动作关系不再伪装成 sameActionInterval=true。
每个 proof obligation 新增权威 sequenceRefs[],每项形如 {stepId, eventRef, actionRef, postFrameRef}。现有 actionRefs/postFrameRefs/eventRefs 只能从 sequenceRefs 确定性去重投影,不能单独签发 satisfied。runner 对所有完整候选的 event-seq tuple 按字典序选唯一最小值交给 Judge,不把宽泛候选并集当作证明。Judge 输出同形 sequenceRefs,且只能从该义务候选序列原样选取,不能改写 step 对应。
Judge 仍需用每步截图确认事件与用户所见一致,并判断跨事件结算和分支语义是否一致;机械匹配只是候选选择器,不具备玩法裁决权。finalPostguard 用封存的 profile/注册表版本重放同一序列,核对每个 payloadHash,并验证 flat refs 等于 sequenceRefs 投影。任一步缺失、倒序、重复 stepId、跨 run、跨 artifact 或无画面佐证都不能 satisfied。
3.5.3 生产者对账门与 Actor 客观进度
五个官方模板、生成 prompt、proof profile 和义务注册表是一条契约链。CI 必须用每个模板的真实交互 fixture 产生事件,再对账该 profile 的所有默认必需义务都至少有一条可达证明;静态扫源码、仅检查字符串或伪造事件 fixture 不算过门。brief 提升为 required 的可选能力必须有对应正例。任一默认必需义务在对应官方模板不可达,就禁止切 v3;不能靠伪造事件掩盖模板实际上没有该用户行为。
ActorView 每轮增加 runner 从“截至当前动作”的 actions/frames/events 增量计算的 objectiveProgress。快照带 candidateOnly=true、单调 snapshotSeq 和内容 hash,只包含必需目标的 id、人读标题、seenStepTitles/missingStepTitles 与 unobserved | partial | observed 候选状态。它不包含 event type、谓词、refs、Judge 结论、accept/reject、分数、修复建议或任何最终状态。这使 Actor 知道还需完成什么可观察用户目标,不再盲目重复动作。
取证封存时,runner 对完整事件集重跑同一解析器并生成最终 candidate snapshot;它必须是最后一个 Actor 增量快照的单调扩展。候选全齐只允许 runner 提前封存,不等于验收通过。
3.5.4 Prompt 输出可消费性门
Prompt 门拆成两个层次。离线协议门先用正式 schema 校验 canonical ActorView/3、VisualTargetSet/1 和 JudgePackage 输入,再用生产 selection parser、resolver、Judge parser 和候选引用边界校验输出;Actor 与 Judge A/B 的 schema 通过率都必须为 100%。Actor 每个 tap/drag 样本都必须引用当前 targetSetHash 和合法 target/cell,裸坐标不过门;两个 Judge 每个样本都必须返回全部 required obligation 和同形 sequenceRefs,且只能引用候选包中的 action-N、动作后 frame path 和整数 event seq。JudgePackage 额外封存只读 textReferenceScope,其 action/frame/event 三组引用由包内事实按出现顺序确定性去重;problems、contradictions、summary 的显式引用只能逐字复制该 scope,义务行仍只能复制本义务候选,missing 义务的 sequenceRefs/evidenceRefs 必须为空。scope 缺失、漂移、多字段或乱序,以及未知引用、跨义务候选引用、旧 a3/f3/e9:... 形态、step 对应被改写和只对 expectedDecision 的输出一律不过门。
真 M3 多模态行为评测另行判断动作选择和 Judge 四态语义,不用行为标签替代协议解析。视觉能力、hash 真伪和画面一致性仍由真浏览器 prompt_eval_gold 校准,prompt gate 不伪装能覆盖它们。
生产 M3 按角色分配推理预算。Actor 使用 max_tokens=20000、thinking 4000;Match-3 难样本在 10000/2000 下以 max_tokens 停止且没有 text,20000/4000 才返回合法校准端点。Judge 输出较短,继续使用 max_tokens=10000、thinking 2000。两者都只消费 Anthropic text block,thinking 只进审计和 usage;Actor 每次调用前按完整 request bytes 与 20000 输出上界做最坏成本预留,实际 usage 结算仍受单掷 ¥1.5 硬帽约束。
Actor 与 Judge A/B 的 Anthropic 请求都必须携带 output_config.format.type=json_schema。Actor schema 只从 contracts/play-loop/actor-selection.schema.json 读取,Judge schema 只从 contracts/play-loop/judge-result.schema.json 读取,runner 不内嵌第二份结构。new-api MiniMax-M3 已实证接受该请求形态,并能按嵌套 Judge schema 返回 puzzle accept 结果;实测一次输出 usage 从约 8000 token 降至 816 token。供应商仍可能在唯一 JSON 外包一层围栏,因此生产 parser 继续只接受裸 JSON 或唯一完整 json 围栏,拒绝围栏前后说明和多块输出。
3.6 双 Judge 与保守合并
双 Judge 是每个游戏 roll 内的两个语义审查槽,不是新增两个游戏 seed。runner 只封存一份 JudgePackage 和一组 post-frame 字节,随后并行调用 Judge A/B;两份结果先分别通过生产 parser、schema、候选引用和跨包文字引用检查,再交给纯确定性的 JudgeConsensus/1。任何 LLM arbiter、多数票、“一个 reject 就 reject”或根据 A 结果改写 B prompt 的做法都禁止。
独立性必须可审计。A/B 使用不同 API client id、session id、policy seed、prompt artifact/hash、输出目录和 raw 文件,不共享 messages、history、cache key 或 user id;两者读取的 JudgePackage hash、图片集合和图片 hash 必须完全一致。policy seed 按 runId | roll | judgePackageHash | judge-a/b 域分离哈希派生。两槽可使用同一模型和网关,但台账必须标 sameModel=true,只能称独立会话和独立检查顺序,不能宣称供应商独立。
每槽规范化后只比较可机械字段:decision、failureClass、按 registry 顺序排列的 obligation status 与 canonical sequenceRefs/evidenceRefs、已通过白名单的 action/frame/event 文字引用集合、是否存在 problem/contradiction,以及 canonical resultHash。自然语言 summary 不要求逐字相同。任一 transport 重试耗尽、空响应、parser/schema/ref/hash 错、输入漂移、独立性失败或模型自报 tester_error,整个 consensus 都归 tester_error;另一槽结果不得降级使用或重新采样挑选有利答案。
逐义务合并只接受同状态、同 canonical refs:
| A / B | satisfied |
failed |
missing |
contradicted |
|---|---|---|---|---|
satisfied |
satisfied | disputed | disputed | disputed |
failed |
disputed | failed | disputed | disputed |
missing |
disputed | disputed | missing | disputed |
contradicted |
disputed | disputed | disputed | contradicted |
satisfied/failed/contradicted 的 refs 必须逐字等于同一 runner 候选,missing 必须双空;同状态但 refs 漂移属于 tester_error/judge_reference_drift,不是语义分歧。任一 disputed 都使本掷至少为 inconclusive/judge_semantic_conflict,绝不能 accept 或 reject。
全局合并固定为:
| Judge A | Judge B | consensus |
|---|---|---|
| accept | accept | 仅当全部 required 合并为 satisfied、两边无 failureClass/problem/contradiction 时 accept |
| accept | 任一非 accept | inconclusive / judge_semantic_conflict |
| reject | reject | 仅当 failureClass、完整义务状态向量和硬证 failureSignature 一致时 reject |
| reject | inconclusive | inconclusive,不能把模型分歧写成游戏失败 |
| inconclusive | inconclusive | missing+missing 为 proof_missing;contradicted+contradicted 为 evidence_contradiction |
| tester_error 或无有效输出 | 任意 | tester_error,禁止单槽降级 |
failureSignature 固定为 failureClass、排序后的失败义务 id、grounded event refs 和 grounded frame refs。全局 off_brief 等拒绝只有双槽同 class、同状态向量、同引用签名才成立,且没有失败义务三证时仍不可 repair。GAME OVER 反事实中,只要一槽 accept、另一槽识别冲突或拒绝,consensus 就只能 inconclusive;即使游戏第二掷双 accept,也不得自动把该语义冲突翻成 accept。
A/B 并行前必须由成本账创建 CostReservation/1,避免两个调用同时越过余额检查。reservation 封存 reservationId、ledgerVersion、judgePackageHash、pricingSnapshotHash、每槽请求字节数、保守 input token 上界、maxOutputTokens=10000、reservedRmb、retryReservedRmb、状态和 settlements。M3 走 new-api Anthropic /v1/messages,开启 2000 token thinking;4000 token 实测会在难样本只返回 thinking 并以 max_tokens 停止,因此请求与成本预留统一提升到 10000。input 上界按完整 HTTP request body UTF-8 字节数计算,Anthropic base64 图片块也计入;该值高于模型回报的 input、cache creation 与 cache read token 总和才允许结算。成本账在同一锁内 reserve(A+B),余额不足、价格快照缺失或估算不可得时不得发请求,直接 tester_error/budget_unavailable。
每槽完成后按 new-api usage 结算并释放预留差额。仅“未收到任何模型内容”的 transport/timeout/5xx 允许原包、原 policy seed、同槽身份重试一次;原调用若无法证明零计费,原 reservation 保持占用,retry 必须另做追加预留,余额不足则不重试。已有内容后的 JSON、引用或语义错误不重采样。输入已封存且无依赖,A/B 在预留成功后并行调用;任一槽失败都不能用另一槽降级。JudgeConsensus/1 审计记录 strategyVersion、package hash、independenceChecks、两个 evaluation 的 prompt/session/seed/raw/parsed/result hash/usage/cost/latency、reservationRef/hash,以及 consensus conflicts、failureSignature 和总成本。
3.7 二掷合并
第一掷 rollOutcome=accept 不二掷;一致 proof missing 的 inconclusive 可用第二掷收集新增硬证;一致硬证 reject 可用第二掷确认可复现缺陷。第一掷出现 A/B judge_semantic_conflict 时可选择跑第二掷供诊断,但不得自动 rescued accept;默认直接保留 inconclusive 以控制成本。第一掷为基础设施类 tester_error 时不进入游戏二掷矩阵,只在相同输入条件下重启失败基础设施一次;仍错即由 finalPostguard 写 tester_error。第二掷使用真正传入 host 的不同 requested game seed,以及独立的 Actor policy seed、浏览器存储和 Actor 会话;其内部再派生新的 Judge A/B policy seed 与 session。host 必须回报 actualSeed,requestedSeed 与 actualSeed 不一致即 tester_error/seed_mismatch。
第一掷 rollOutcome |
第二掷 rollOutcome |
mergeCandidate |
|---|---|---|
accept |
不运行 | accept |
inconclusive,无已证实缺陷 |
accept 且出现第一掷没有的新硬证 |
accept,标记 rescuedByRoll=2 |
inconclusive/judge_semantic_conflict |
任意 | inconclusive;模型语义冲突不能由新 seed 自动翻案 |
reject |
同一缺陷 reject |
reject,可进入唯一一次 repair |
reject |
accept |
inconclusive;成功 seed 不能抹掉已证实缺陷 |
inconclusive |
reject 或 inconclusive |
均为 inconclusive;一次语义拒绝不足以证明可复现 gameplay 缺陷 |
| 任意两掷事实矛盾 | 任意 | inconclusive,待人工,不修游戏 |
| 任一掷只有模型 pass、无完整硬证 | 任意 | 该掷不可能为 accept |
基础设施/图像 tester_error |
原条件重试一次仍错 | tester_error,不进入 gameplay repair |
一次完整硬证可以证明存在可玩闭环;随机种子稳定性另在 25 局基线和 prompt_eval_gold 回归中衡量。若某一掷已经证明崩溃、状态损坏或错误结算,另一掷成功不会抹掉该缺陷,mergeCandidate 必须为 inconclusive,再由 finalPostguard 写入并保留 seed 级问题,不得直接放量。
gameplay reject 与 repair 必须来自两掷相同 failureClass、失败义务状态向量和 failureSignature。唯一允许单掷直接形成 reject 的是 runner 可确定重建的契约矛盾,例如同 workId 的完成自报与有序步骤数量冲突;它必须标 deterministicContradiction=true、repairEligible=false,不与 Judge 语义 reject 混用,也不能调用 Writer。
3.8 最多一次 writer repair
repair 只接受带硬证引用的 final reject。条件固定为 verifiedReject && repairEligible && repairCountAcrossParentChain == 0;四门明确代码错误、两掷一致的玩法阻塞、硬证成立的 hollow/off-brief 可修一次。单纯缺 proof、inconclusive、Actor 协议失败、Judge 无法裁决、图像通道故障、端口或浏览器环境故障不得调用 writer。
writer 只收到 brief、失败义务、客观事件、动作和帧引用,不收到 Judge 的推测。v3 接线时必须切断 CLI 与 Service finish 点的旧九门玩法 resume,只保留生成期 check/build 修复;否则会形成两套自动修复环。修复完成后重新构建并创建新 run,从 PRECHECK 全量重验;旧 run 不得增量续写。parentRun 整条链第二次仍未通过即终拒或待人工,不再自动修。
3.9 失败归因与后端兼容
outcome 是权威结果;failure layer 只是向旧消费面投影:
failure.layer |
何时使用 | 可否 repair |
|---|---|---|
none |
接受,且所有硬证完整 | 否 |
mechanical |
A/B/C/D 任一明确产物失败 | 明确产物缺陷时一次 |
gameplay |
两掷一致证明 broken、hollow、off-brief 或必需闭环不可达 | 一次 |
tester_degraded |
兼容投影:新 outcome=inconclusive/tester_error |
否,待人工 |
failure.reason 只写事实和引用,不写猜测。failure.subtype 区分 floor_gate、proof_obligation_failed、off_brief、action_protocol_exhausted、judge_error、roll_conflict、environment_error 等可检索原因。
迁移采用并列版本兼容。playtest/3 是新签发真相层,playtest/2 是冻结的旧证据层;run-summary 继续写 accepted、ok、playtest、judge、failureLayer、failureReason,但只能由当前版本 finalPostguard 的 decision 单向投影。judge 从 playtest/3 起只镜像 JudgeConsensus/1,不能镜像 Actor 自裁或任选 A/B 单槽。result_out 把 schemaVersion、outcome、proof 状态、roll merge、rescuedByRoll、evidence refs 和 firstPlay 写入 trace.playtest,把 consensus 摘要写入 trace.gameplayJudge。
Java 读侧明确按 outcome 处理:accept 的 playability=1,reject=0,inconclusive/tester_error=0.5;0.5 只作观测分,任何 outcome != accept 的任务无论其他维度多高,都不得进入 ready/publishable。GenMetrics 分别记 playtest、tester_inconclusive、tester_error 桶,rescued roll 单列计数。未知 schema/outcome、证据引用失效或兼容投影矛盾一律 fail-closed,不得按 accept 解释。Python 序列化、Java 契约、ReadinessScorer 与 GenMetrics 都须有回归测试,其中必须包含“其他维度接近满分但 outcome 非 accept 仍不可发布”的组合边界用例。
3.10 v3_shadow 到 v3
v3_shadow 的新生产 run 只运行 v3,不执行 v2 裁决;所有 shadow 样本处于内测隔离,自动发布冻结,decision 只用于校准。v2 仅允许离线重放历史样本,不能作为 shadow 或生产权威,也不能靠已知样本黑名单继续放行未知分歧。
切换 v3 后,accepted 和 ok 由 v3 decision 统一写入。回滚只允许退回 v3_shadow 并冻结自动放行,不允许把已证伪的 v2 自裁重新设为生产权威。
3.11 2026-07-13 实施差量
实现收口时又对照了契约、Node runner、Python 终裁和 Java 发布读侧,以下边界已由代码和定向回归锁定:
- 验收成本先求有限非负数值子项的精确和,再按十进制
ROUND_HALF_UP在顶层统一保留五位小数;不再把各段先舍入后相加,也不依赖语言默认 round。跨语言向量0.11684088统一为0.11684,半位向量0.015625统一为0.01563。repair 请求只提交本轮 writer 增量,历史成本从 sealed parent decision 推导,调用方不能重置父链。 - 双 Judge 只有一致确认同一
broken、hollow或off_brief,且 failureClass、义务状态向量和硬证签名一致时,单掷才可reject。任一槽接受或签名分歧只能合并为inconclusive。没有失败 obligation 三证的全局拒绝不会触发 writer repair,防止把语义判断当成可盲修的代码定位。 - runner 在每个生产动作记录中固化
hasCausalGameResponse。动作后只有观测到状态变化,却没有可信 actionId 的延迟事件,会带观测动作、类型、时间和原始序号写入excluded-unattributed-event审计记录,且recoverableByLaterAction=false;后续 wait 不能倒签归因。 - Python 的
equals和oneOf与 JSON 类型严格对齐,布尔值不再与数字 0/1 等价。wait 只开启观测窗,不创造因果;跨步证明除sameValue外,TRPG、解谜和经营还分别强制sourceFloorVisitId、sourceLevelVisitId和dayId。缺少这些关联 ID 的旧 transcript 只能作历史对照,不能复用为 v3 通过证据。 - 验收从受信文件树生成
artifact-snapshot/1,runner 和本地服务只读这份内存快照。本地锁与进程锁保证同一 run 不并发改写,taskBindingHash和acceptanceRequestHash锁定任务身份。发布前必须重算当前产物 hash 并与 active v3 accept 的artifactHash相等;v3_shadow、未知协议、旧证据和 hash 漂移都在发布边界 fail-closed。 - Java 发布闸不再只信回调 trace 自报协议代际:任务模板属于当前后端白名单时,后端直接钉死预期
playtest/3;回调即使把 schema、mode、outcome 和根级 marker 全部剥空,也只能得到downgrade_detected,不能回落旧accepted/pass。双 Judge 的 reject 签名只绑定失败分类、失败义务状态向量和 grounded event/frame refs;自然语言保留在分槽审计中,不参与逐字相等,避免同义改写制造假分歧。成本账将 Judge A/B 分槽记录,并允许 provider token 数恰好等于保守上界。
旧 playtest/2 曾有 Python 628/628、Java 83/83、Node 220/220 和五模板浏览器检查记录,只能作为历史实现证据。playtest/3 本轮已重跑 Node 85/85、Python 相关编排 264/264、Java 85/85、契约正样本 39/39 与负样本 102/102、视觉候选 9/9,Actor/Judge 离线消费门和生产 parser fixture 全绿。mini-desktop /gstack 真实打开解谜页时,页面渲染、控制台和网络均正常,window.__gameBooted=true;runner 只监听 __genBooted 才导致 browser_boot_timeout 假阴。runner 现同时监听两种启动信号并兼容 __gameBootError。TargetGuide 的确定性噪声已分三层收敛:后画父容器不再擦除先画紧框,region 最小边长收敛到 24px 以排除文字笔画级候选,Actor 可见投影再隐藏多子框父容器与近套叠色块并清除 primary 内的 g01 网格线;普通 wait 契约同步收窄为 100–600ms。这些证据仍只证明工程边界,不计入 fresh 25、Prompt 校准、游戏内容金标或生成成功率分母。
2026-07-15 的当前状态为 playtest/3 工作区实现已落、收口验证与 Prompt 校准阻断。Actor 使用 VisualTargetSet/1 + ActorSelection/1 + ActorView/3,runner 解析目标后才派发坐标;Judge A/B 使用独立 prompt、session、seed、逻辑 client 和输出目录,在一次原子成本预留后并行判读,只有保守共识可以进入单掷结果。合法交互连续无响应已按评审修正为 inconclusive/interaction_unresolved,不再误记为 tester error 或玩法失败。playtest/2 schema、validator 与已有证据冻结只读,不能升级成 active accept。
真模型结果尚未整体达到进入基线的条件,但 Judge 独立 PromptEval 专项门当时已经收口。R1 把所有注册 profile 事件分成当前 proof 与跨 profile observation,使 off_brief 样本可经生产事件边界到达 Judge,同时保证 observation 不参与义务候选;parser 锁定 candidateState/status/decision,Gate2 纳入语义标签后,Judge A/B 使用 3.0.4 连续四轮各自 schema 与行为均为 6/6,共识假阳为 0。四轮审计包分别落在 20260715T205241、20260715T205605、20260715T205854 和 20260715T210221 开头的 A/B raw run。该结论只覆盖固定 PromptEval fixture;r8/r10 的真实生成集成链仍出现 Judge 槽错误,因此 Judge 输出格式稳定性仍是完整总门阻断项。
Actor 已用 PromptEvalAudit/2 在相同 exact request bytes、Prompt、fixture、model、temperature 和逐题 seed 下完成两次真网复跑:20260715T133140.676934Z-p69938-n1784122300677172000 为 3/5,20260715T134047.408075Z-p88938-n1784122847408325000 为 4/5。五条 request body SHA-256 逐条相同,shop、wait、2048、Match-3 的响应仍发生翻转;provider 只返回模型别名和不同 request id,没有 system fingerprint。这证明固定 seed 不提供结果确定性,也证明单次 4/5 可能只是幸运采样。修复前门曾把第二轮误记为 allGreen=true;R1 后单轮与双轮都固定拦截,必须连续三轮同请求满足 prompt_eval_gold 聚合门才能建线,且第四轮才能确认。Actor 前三轮要求 schema 15/15、每轮至少 4/5、合计至少 12/15,并且每个 evalKey 至少 2/3 正确;等价正确动作不算漂移,同一题稳定答错则不能建线。PromptEvalAudit/2 两轮均为 auditComplete=true/requestReplayable=true,凭据扫描无命中;早期 /private/tmp 现存账本与 raw 已按证据等级恢复到 contracts/prompts/eval/recovered-evidence/20260715/,但一律保持 legacy-v1/auditComplete=false。
Actor 的 Simon 已从 3000ms 改为协议内 wait;renderer 擦除紧框、文字碎片候选和 boot 信号三类确定性 harness 假阴已修。shop 的完整 TargetSet 仍保留 24 个 region 与原 r15/targetSetHash,Actor 可见投影已从审计中的 25 个顶层 target 收窄到 15 个:r15 保留,吞入下半屏的 r23、色块碎片 r16/r17 和重复父框 r21 不再进入 catalog/guide,g01 仍保留为 fallback;3.0.4 又把 region ID 改为 leader 直连 safePoint,几何绑定问题已转入复测。
两次 3.0.4 endpoint raw run 暴露的 Match-3 阻断已经按 §3.3.2 收敛为匿名棋格矩阵、合法 pair 和真实双 tap 结果,不再让通用模型逐格识别棋盘。实施过程中确认了五类独立假阴:TargetGuide manifest 与 canonical 自哈希混用;View/4 已投影对象被二次投影后丢失 match3Swaps;旧 prompt 未约束 ActorSelection/2;恢复策略变量越过块作用域;首击白色选中环被感知器当成新棋子类别。对应修复分别落在 hash domain、可信 View/4 内存身份、版本化中文 prompt、每掷恢复策略和严格白色 source-over overlay normalizer。normalizer 只接受冻结的 40×40、472 像素支持集与每通道残差不超过 1 的白色描边;原始 crop hash 保持不改,非白环、稀疏环、格外变化和几何漂移固定为 indeterminate。
2026-07-16 的 attempt-016-current-code-final 使用真实 Chromium、固定 390×844 视口和项目锁版 Python 视觉环境执行四轮。四轮均为第一次 Actor 输出合法 ActorSelection/2,恰好派发 action-1/action-2,BoardIdentity=equivalent,无 reset,第二击连续产生同 moveId 的 puzzle.swap-committed 与 puzzle.match-formed,puzzle.match3-valid-swap 最终为 satisfied;单轮成本 ¥0.08183–0.13148,总计 ¥0.41007。校准脚本新增专项硬闸,runSingleRoll 仅成功封存不再被记作完成;动作账、双事件、动作组、棋盘身份、审计终态、首尝试和专项 proof 任一不闭合即 match3_specialty_gate_failed。同时修复 Judge 文字引用的贪婪路径解析、optional 义务污染共识和“缺证说明必须引用不存在事件”三类 parser 假阴。全部 _shared Node 测试 190/190、视觉 Python 39/39、契约正例 95/95 与负例 205/205、docs-gate 均通过。
2026-07-16 的 attempt-019-transcript-pixel-proof 把 post-first perception audit 的原始字节、逻辑引用和 SHA-256 纳入可信 artifact ledger,并由 BoardIdentityCheck/1 从原始 audit 独立重建 OverlayNormalizationEvidence/1。重建核对首击前后 frame、TargetSet、Projection、firstEndpoint、完整感知配置、固定 classifier 身份、helper path/args、runner 独立传入的三个物理输入路径、两次进程退出状态、stdout/stderr 原始字节与哈希、stdout 解析结果、Projection 原始片段哈希、归一化摘要和 40×40 support mask;校准门再次回读磁盘 audit 并复算 hash/auditBytes。bundle validator 固定 canonical overlay config hash,并从 390×844 initial/post-first PNG 独立复算像素差、透明度扩散和不透明像素比例;完整重签 audit→Board→Group→roll/proof/Judge 为假 not-needed、同步改写 audit/helper 路径或自报放宽阈值仍被拒绝。四轮真实 Chromium 复测均为 normalized,每轮 changedPixelCount=472、outsideSelectedCellCount=0、maximumReplayResidual=1,八次 helper transcript 完整且同轮 Projection 原始片段一致;四轮总成本 ¥0.41837。当前回归为 _shared Node 195/195、视觉 Python 39/39、契约正例 95/95 与负例 211/211;第四轮独立一致性复审确认此前两项路径与配置 P1 均已关闭,未发现新的 P0/P1。
这组 4/4 只证明确定性 fixture 的专项协议与执行闭环,不是生成成功率,也不是生产开闸证据。normalizer canonical 绑定已经闭合,五个真实生成 Match-3 样本也已登记为 harness_fixture;它们的人工正反复核与 Actor/Judge prompt_eval_gold 尚未收口。当前正式 game_content_gold 为 1 款:gac-shanhai-xingji,签认范围仅为《山海行纪》地图1《裂谷原》完整 20 分钟纵切版;它不改变五个 Match-3 样本的 fixture 身份,也不替代其余验收。fresh 25、historical 11、production shadow 20 仍未启动,生产 runtimeEligible=false 保持不变,发布继续冻结。
2026-07-16 首批五款真实生成候选暴露了生产者与验收契约错位。gold-m3-porcelain-r2 的首击前后只有首格金色填充描边及其越过格边界的 307 像素 halo、棋盘外操作提示变化;棋盘状态和其余 63 格棋子没有推进,源码首击分支也只更新 selected。但题面仅要求“选中态不得改变图标类别”,没有要求复用 40×40 白色描边;生成结果使用 46px pitch、半透明金色填充和 3px 描边,必然被冻结的 v1 normalizer 拒绝。该结果记为 inconclusive/unsupported_selection_overlay:它不是生成游戏失败,也不能作为 accepted。v1 不原地放宽,不关闭格外变化门,不通过提高感知阈值掩盖选中态。
MVP 的最小收敛路径是让标准 Match-3 生产者复用受保护、已校准的交互能力。现有 _template-puzzle 是规则匹配谜盘,并不自带 Match-3;canonical 40px 几何和白色 selection overlay 当前只存在于已通过四轮真浏览器校准的 Match-3 fixture。实施把 fixture 的 390×844、8×8、40px pitch、格心计算、canonical cell shell 和 3px 白色圆环提炼为 match3-producer-profile 插件,由 puzzle 的 L1 host-config.js 实例化并扁平注入,Writer 无权改写插件实现或宿主 wiring。插件提供 identity()、geometry()、drawCellShell(g,cell)、drawSelectionOverlay(g,cell) 与 themeSafeBounds(cell);选中环下方 substrate 由 shell 固定,主题图标只能画在不接触 472 像素 support mask 的安全内区。match3.orthogonal-swap-v1 增加 producer capability 的 id、version、config 和 configHash。request、provenance 与 binding 不重复保存 producer config,只携带既有 profileId 和 registryVersion,并从同一 registry 确定性解析 producer identity;可信宿主直接读取真实插件 probe,与解析结果对账。L3 自报或 _forensicsView 不参与身份判断。
真 Chromium 对 producer 草案的反证表明,arc(radius=18)+stroke(width=3) 在固定暗色 shell 上仍会随格位得到 475、468 等不同 changedPixelCount;历史 fixture 的 472 不是 Canvas stroke API 的稳定保证,而是特定栅格位置、底色和抗锯齿舍入的共同结果。因此 capability 不调用浏览器 stroke 栅格化选中环,改为按 v1 normalizer 已冻结的 40×40、472 像素 supportSpans 逐像素写入纯白 mask。producer config 显式绑定 maskSize、supportMaskHash 和 expectedChangedPixelCount,插件测试从 spans 复算 hash 与像素数;主题安全矩形内缩 12px,保证任何图标像素都不接触最内层 support。这个变化保持 v1 识别的视觉白环和像素证据不变,同时消除位置与底色舍入变量。
源码调用和 capability 自报都不是像素证据。专项 runner 在调用 Actor 前先启动一次性隔离 Chromium context,使用与正式 roll 完全相同的 artifact、seed、390×844 viewport、interaction registry 和 runtime identity,从 resolved SwapSet 机械选择首个 canonical firstEndpoint,封存首击前后 PNG、事件区间和可信宿主 capability probe,再由 v1 normalizer 独立复算。preflight 完成后销毁整个 context;正式 roll 必须在全新 context 启动,且初始 frame hash、lattice geometry 与 capability probe 和 preflight 初始证据逐字一致,否则不得复用结论。lattice geometry 不是任意 8×8 摘要:runner 必须从 producer config 的 origin、pitch 和行列数生成格心数组,按 match3-lattice-geometry/1 复算唯一 geometryHash。只有 capability 与该 geometry 都命中 registry,且 normalized、changedPixelCount=472、outsideSelectedCellCount=0、maximumReplayResidual≤1、棋盘几何不变、首击无业务事件,才允许创建 Actor client 和成本预留。
producer 绘制自身也必须先站在正确的逻辑像素基线上。宿主会把 390×844 逻辑视口映射到 DPR 放大的 Canvas backing store;producer 不能为清理 L3 遗留状态而无条件 setTransform(1,0,0,1,0,0),否则 DPR=2 时棋格底壳和选中环会缩到左上四分之一区域。插件必须从 canvas.width/390 与 canvas.height/844 推导相等的正整数基线比例,在 save/restore 内只归一 transform、alpha 和 composite;backing ratio 不合法直接拒绝。DPR=1 的插件独立页和 DPR=2 的真实宿主都要通过同一组 shell 格心、472 像素选中环、支持集外零变化与重放幂等证据。
VisualTargetSet 只是操作候选,不应把通用 OpenCV 的棋盘漏检伪装成游戏失败,也不应把 producer 坐标伪装成 OpenCV 观测。已通过 registry、宿主 probe 和 configHash 三方对账的标准 Match-3 使用独立的 match3-producer-seeded-targets@1.0.0 生成器身份:它保留 OpenCV 的 region 候选,但只用 producer config 的 origin、pitch 和行列数提供待验证坐标轴。renderer 随后必须在当前真实 PNG 的每个 canonical crop 内独立扫描受保护 cell shell 的实际前景和质心;只有真实命中的格才进入 observedCells,coverage、axis residual、size CV 和 spacing CV 全由这些像素命中复算,不调用下游棋子类别感知器,也不无条件填充 64 格。producer lattice 带 geometrySource 绑定 capability id、version、configHash 和 geometryHash;OpenCV lattice 保持旧形状。producer lattice 唯一优先,不与 OpenCV lattice 并列,落在其 bounds 内的 region 继续抑制,g01 永久保留。最终 TargetSet 先封存,guide 和 manifest 再从它生成,禁止 Node 事后改 JSON。
seeded generator configHash 的 canonical 内容固定为 OpenCV 完整配置、producer capability 全量内容和合成算法版本,以 generatorConfig/1\0 作 domain separation。renderer、Node runtime、Python perception 和目录 validator 都必须从 canonical interaction registry 独立复算并只接受精确的 id、version 和 configHash;仅校验 64 位 hash 形状不够,任意自签 lattice 必须被拒绝。这个 lattice 只回答“应去哪里看和点”;棋子是否真实存在、64/64 是否可分类、首击后是否只有允许的选中环变化,仍必须由只读感知器从当前真实 PNG 独立复算。未带 producer capability 的普通页面和 puzzle 仍只允许 opencv-visual-targets@1.0.1;未对账 capability、非唯一 lattice、canonical geometry 漂移、shell 观测支持不足或逐格感知不完整都 fail-closed。
真实生成样本校准进一步证明,通用前景比例不能直接套到受保护 producer shell。通用 OpenCV lattice 继续使用原来的前景比例范围;producer-seeded 路径使用独立的 70..200 千分比前景范围,并把该差异纳入自身 generator configHash。该阈值只用于确认 canonical crop 中确有受保护 shell,不参与棋子类别判断。实际 PNG 的逐格扫描在旧 r2 样本只命中 53/64,在修复后的 r3 样本命中 64/64;这说明旧 TargetSet 漏格属于 harness profile 假阴,而不是游戏少画了十一格。阈值、几何、shell 观测和类别感知仍分别封存,禁止把 producer 坐标先验直接提升成“64 格均已看见”的结论。
隔离过程落盘 Match3ProducerPreflight/1,绑定 artifactHash、taskBindingHash、acceptanceRequestHash、interactionBindingHash、registryVersion、seed、环境 identity、expected/probed capability identity,以及已经实际产生的 frame、事件、lattice、SwapSet 和 normalizer 证据。executionStage 记录最后完成边界;Chromium、CDP、截图或视觉链在中途失败时,未来阶段字段必须为 null,normalizer=not_run 时 ref/hash 与像素数也必须为 null,不能为满足 schema 伪造占位引用。compatible 的原始字节 ref/hash 进入正式 Match3RollInteractionAudit/1,目录 validator 复算 preflight fact 与文件 hash,并逐字段核对 game、artifact、request、task binding、interaction binding 与 seed;不 compatible 或任一身份分叉都不能创建正式 Actor。incompatible 由上层编排器形成零模型成本终态 inconclusive/profile_contract_incompatible,不伪造 SingleRollFactV3、Judge 或 cost reservation;schema/hash/helper、request/provenance/binding/registry/probe 漂移归 tester_error/profile_contract_error,Chromium、CDP、截图或视觉链失败归 tester_error/environment_error。因为 v1 仍按 whole-frame 复算,绑定该 producer profile 的游戏暂时不得在首击后改变棋盘外状态文案;这是 v1 的临时 UI 约束,不是一般游戏正确性规则。若产品以后需要多种棋格尺寸或选中风格,必须新建 normalizer v2 与对应 interaction profile,以真实浏览器 prompt_eval_gold 正例和“首格换类、相邻格变化、遮挡图标”负例重新校准,不能把真实生成样例倒逼成 v1 的宽松阈值。该 capability、binding、preflight 事实包和退出路由通过真实生成 harness_fixture 正反校准前,生产 runtimeEligible=false 保持不变。
preflight 的环境日志必须同时记录 CSS 视口、Canvas backing store、scaleX/scaleY 与浏览器 devicePixelRatio。首个真实样本显示 CSS 为 390×844、backing 为 780×1688、内部比例为 2,而浏览器对外 devicePixelRatio=1;只记 DPR 会把宿主主动放大的 backing store 隐去,进而把 producer 缩放错误误归为视觉感知失败。日志从环境建立、浏览器连接、capability probe、初始截图、首击派发、post 截图、normalizer 到最终事实逐阶段追加;任一早错也必须封存 nullable tester_error 事实,不能只留下进程尾日志。
2026-07-17 的真实生成 gold-m3-gem-r3 从 r5 到 r10 给出了完整的根因链;证据目录的 attemptId 沿用了 20260716 命名,不代表实际生成时间。r5/r6 的棋盘感知已解析,但首击同时改写棋盘下方提示,导致选择态支持集外出现 1188 个变化像素,属于产物违反 producer v1 约束;修复后 r7 的选择态为 472 个支持集内像素、支持集外为 0。r7 又暴露事件在 update 动画结束后才发出,虽然类型和值正确,却没有可信输入 actionId;这不是 runner 漏绑,而是生产者把输入结果放出了第二次点击的同步因果边界。生产 prompt 要求第二次合法点击在 handleTap 同步调用栈内完成交换、确定性连锁、计分、目标判定和所有直接输入证明事件,update、RAF 与 timer 只消费视觉队列。静态门只对可机械识别的边界负责:首击副作用、selection 渲染、已发现事件生产点的同步可达性和 swap-committed revision 字段形状;它不证明连锁、计分或目标判定正确,也不保证所有事件名称必然齐备,最终仍由真实动作、事件载荷、截图和 proof obligation 交叉裁决。
r8 已得到绑定 action-2、共享 moveId=m1 的 puzzle.move-applied、puzzle.swap-committed、puzzle.match-formed 三事件,但 Judge A 因无关义务的槽格式错误把最终 proof 投影成 missing。专项校准验证的是可机械复算的双击闭环,因此优先读取 collection-proof.json 中的 candidate;Judge 槽错误继续原样保留为独立 tester error,不得覆盖机械候选,也不得被机械候选反向宣称为 Judge 通过。r9 随后发现生成修复把 swap-committed 的 boardRevisionBefore/After 回归成 boardHash.before/after:事件存在、同步归属也正确,但注册表的 revision 递增谓词不成立,resolver 正确给出 contradicted。这说明“同步可达”静态门仍可能假阳。静态检查现同时约束 swap-committed 顶层 revision 字段,并拒绝相同表达式、相同常量和可判定的倒退常量;运行时 proof 继续负责最终递增验证。
r10 在真实 Chromium 中完成单轮专项闭环:第一次 Actor 输出即合法,恰好执行 action-1/action-2;BoardIdentity=equivalent,选择态归一化双跑一致;三事件均绑定 action-2,swap-committed 为 revision 0→1,match-formed.matchedCount=3,机械候选引用事件 2、3 并为 complete。artifactHash 为 c45e662011a9ac6ee5b655c61d821e971b0dfd78ea98a15b876e41e31db4806b,单轮模型成本 ¥0.11256,证据目录为 game-runtime/evidence/match3-actor-calibration/fresh-gold-m3-gem-r3-20260716-r10-contract-payload/。同轮 Judge B 的语义判断正确,但 summary 逐字抄写带双引号的 UI 文案且没有 JSON 转义,parser 因此给出 judge_slot_error;严格 parser 没有自动修补或单槽降级。
Judge A/B prompt 升至 3.0.13,要求字符串不逐字抄 UI 文案,不在字符串内部使用双引号、反斜杠或真实换行,只复制结构化 evidence token。r11 使用同一 artifact 和 seed 复测,两个槽均得到合法 JSON,独立性检查全部通过,共识为 inconclusive/proof_missing:puzzle.legal-move 与 puzzle.match3-valid-swap satisfied,目标、通关和成绩三项因本轮只执行一次交换而保持 missing。r11 单轮成本 ¥0.07889,证据目录为 game-runtime/evidence/match3-actor-calibration/fresh-gold-m3-gem-r3-20260717-r11-judge-json/。这证明已观察到的未转义故障在一次真实回归中消失,不证明新 prompt 已满足连续三轮建线和第四轮确认的稳定门;旧 Judge baseline 不得自动继承到 3.0.13。
同步静态门的复审还发现具名 timer/RAF 回调可能与 handleTap 共用同一事件 helper,形成“双可达但只看 handleTap/update 根”的假阳。门现把 setTimeout、setInterval、requestAnimationFrame 与标准 timerScheduler.schedule/after/every/sequence 回调作为不可信异步根;具名、内联和 sequence.run 回调只要可达事件生产点即拒绝,纯视觉回调继续允许。动态调度别名、.bind()、跨文件回调和未登记的自定义调度器仍不在轻量调用图的完备证明范围,最终运行时 action provenance 继续拥有否决权。
真实生成批还暴露了 generation-only 环境接线缺口。标准 Match-3 的固定 host-config 只有在页面求值前得到 match3.orthogonal-swap-v1 才会装配 producer;旧 smoke 没有注入该 runner 输入,正确产物也会在 capability 处失败。smoke 后来通过 CDP Page.addScriptToEvaluateOnNewDocument 在导航前注入 profile,但这只修了验收器入口,没有修产品直链:普通浏览器打开 staged URL 时 window.__playtestInteractionProfileId 仍是 undefined,五款都会因 producer 未装配而 boot 抛错或首帧停住。可信 scaffold 现把批准的 per-package profile 编译进 Writer 不可写的 entry-bundle.js,普通浏览器无注入时使用该默认值,runner 显式输入仍优先覆盖;普通 puzzle 缺省为 null,不按 gameId 猜 profile,也不无条件启用 producer。共享 index 模板与此后新生成或重建的页面保存 __genBootErrorStack,smoke 输出 bootStack,Match-3 动作组的 runtime-error.json 也完整落盘 errorDetails 和 errorStack。旧 staged 页面不会因模板修改自动获得新字段或默认 profile,必须重建后才可依赖。旧 candy-r1/gem-r1/idle-r2/porcelain-r2 在当前协议下均因 host-config 没有 producer probe 而零模型成本 fail-closed,不能拿旧页面补写 profile 后冒充当前合格 fixture 或证据样本。
静态首击门曾把 overlay helper 内的局部 cell 别名传播到 sibling drawBoard/drawGem,使 porcelain 的固定棋盘绘制出现数十条假阴。修复后别名只在函数作用域传播,分析只从真实 render 入口展开;纯 overlay 包装链必须最终只调用成员 drawSelectionOverlay,且不得有非局部写入、其它绘制、状态推进或返回值泄漏。if(selected) drawBoard、把 selected 传给普通绘制、selected 改 HUD/文案和 early return 跳过固定绘制继续拒绝。candy 的跨文件 renderPlay({selected}) 无法由轻量词法门完备证明,因此产物改成固定 render 与 scene 入口 canonical overlay 分离;没有为单款游戏增加函数名白名单。
gold-m3-candy-r3 先后验证了 environment、context 和 harness 三类独立根因。最初 generation-only smoke 在 profile 注入后暴露 L3 棋盘构造错误:当前行尚未放入 board 就读取 board[row],且单元格写成数字而下游读取 {kind};修复后 boot 与帧推进恢复。首轮 preflight 随后显示菱形、星形、水滴前景覆盖只有 52–63 千分比,蓝色空心环虽有 92 千分比却把格心画回 substrate,分别触发覆盖不足和中心非前景。这是产物视觉违反 producer 感知契约,不是应放宽阈值的 harness 假阴。当前提供给 Writer 的 producer API 已补充中心实心、单连通、70..200 千分比、同类逐像素同构和禁止柔光/随机纹理等约束。修复图标后,r2 的 64 格、6 类、16 个合法 swap、白环 472 像素和 BoardIdentity 均闭合,但专项门又把事件数组硬编码成恰好三项,错误拒绝合法二连锁 move-applied → swap-committed → match-formed → match-formed。门现要求前两项固定、后续至少一个且全部为同 actionId、同 moveId 的 match-formed;错误附加事件、错序、跨 action 和 moveId 漂移继续拒绝。r3 fresh-gold-m3-candy-r3-20260717-r3-cascade-gate-fixed 在线复测专项门通过,成本 ¥0.09377;双 Judge 有效且独立,共识因单交换缺目标、通关和成绩证据而保持 inconclusive/proof_missing。
gold-m3-porcelain-r3 给出了感知和玩法循环的另一条真失败链。r1 的 64 格前景均可读,但六类共用柔光与细碎多色纹理使类别分离不足;去掉柔光后 r2 剩珐琅 15 格只有 58–60 千分比,仍是产物真拒绝。珐琅改成中心实心相连轮廓后 r3 preflight compatible,真实第二击却只持久化到 event_contract_error。源码复核定位到命中格只标 clearing、没有从逻辑盘面清空;按现有循环控制流,原三连会被后续检测重复命中并持续写事件,这解释了运行时拒绝。boot-only smoke 和静态 check 只覆盖各自声明的启动与结构职责,本来就不承诺发现该运行时缺陷;只有上层把它们误当成玩法通过时才会形成假阳。修复为先置空命中格、再按列压实和补新后,r4 fresh-gold-m3-porcelain-r3-20260717-r4-chain-fixed 完成 64/64 感知、Actor 首尝试、同 action-2 的三事件、revision 1→2、matchedCount 3、BoardIdentity equivalent 和专项门通过,成本 ¥0.07624;双 Judge 同样正确保持 inconclusive/proof_missing。64 轮异常兜底会重建盘面但未单独增加 boardRevision 或事件,正常 r4 未触发,仍作为待消除风险保留。
gold-m3-fruit-r3 证明了“Writer 读到约束”不等于“产物遵守约束”。生成 closeout 在两次 attempt 后以 ¥9.9873 得到 check/build/stage/smoke 全绿产物,但源码仍曾在无效交换分支写 move-applied/swap-committed 并递增 revision;固定 seed 负例修复后封存为盘面恢复、movesLeft=19、业务事件 0、revision 0,证据在 game-runtime/games/amgen-gold-m3-fruit-r3/evidence/invalid-swap-negative-proof.json。首轮视觉 preflight 又显示草莓、西瓜约 66 千分比,葡萄只有 25–30 千分比且中心为空、前景分裂;两次定向修复仍有 68–71 千分比和多组件残留。最终把葡萄收敛成一次填充的中心实心闭合果簇后,r4 fresh-gold-m3-fruit-r3-20260717-r4-solid-cluster 完成 Actor 首尝试、三事件、revision 0→1、matchedCount 3、BoardIdentity equivalent 和专项门通过,校准成本 ¥0.10108。该链说明 prompt/API context 只能降低错误概率,不能替代 generation closeout 的真实 producer perception。
gold-m3-rune-r3 同时暴露 producer shell、点击几何和图标感知三类产物错误。生成成本 ¥9.2486、两次 attempt,check/build/stage/smoke 全绿;但点击换算多加了半个 pitch,第一列格心会映射到第二列,固定 seed 无效交换负例修复后同样封存为盘面恢复、movesLeft=19、业务事件 0,证据在 game-runtime/games/amgen-gold-m3-rune-r3/evidence/invalid-swap-negative-proof.json。r1 又因全屏后处理在 drawCellShell 之后改写 canonical shell,renderer 从真实 PNG 得到 0/64 支撑;旧分类把这类 visual_target_render_error 误写成 environment_error,现已收窄为 incompatible/profile_contract_incompatible,其它 Chrome、端口和 helper 错误仍保持环境错误。恢复 canonical shell 后,r2 的内孔、描边和分离花瓣造成 31–42 千分比、格心为空或前景碎裂;r3 只剩一类 69 千分比的边界失败。六类符文改成不同主色和外轮廓的单一中心实心图形后,r4 fresh-gold-m3-rune-r3-20260717-r4-foreground-fixed 完成 Actor 首尝试、三事件、revision 0→1、matchedCount 3、BoardIdentity equivalent 和专项门通过,成本 ¥0.08174。
fruit/rune 两款生成共花 ¥19.2359,校准共花 ¥0.18282;五款生成批累计 ¥39.1910,未触发 ¥75 硬停线。两款最终都增加 64 轮同步连锁上限,但尚未通过故障注入验证上限路径。更重要的共同缺口是 generation closeout 仍只跑 check/build/stage/smoke,没有在 Writer 收口前执行 producer perception preflight;因此不可感知图标和 canonical shell 改写会在模型退出后才被专项校准发现。该门需要作为下一项编排设计接入,不能用继续扩 prompt 代替。
完整回归还捕获了一个真实 Chromium harness 假阴。网络防火墙收到 Target.attachedToTarget 后会异步发送 Runtime.runIfWaitingForDebugger,旧测试紧接着读取 resumedChildTargets;命令已经发出但 Promise 尚未完成时,快照仍为空。延迟 100ms 的 fake CDP 可稳定复现,真实 Chrome 的并发回归也曾命中一次。防火墙现跟踪所有待完成的 child resume Promise,收口方必须先调用 awaitChildTargetResumes(),再执行 assertClean() 和快照断言;完成记录只在 CDP 命令成功后写入,不能提前记账伪造成功。失败断言同时输出 attached target 与 firewall audit,后续可区分事件未到、命令仍在等待和命令失败。修复后定向延迟回归、共享 Node 217/217 及真实 Chrome 连续八次复跑均通过。
Python Service v3 回归同时揭示了协议迁移混用:编排器仍签发冻结的 acceptance-request/1,却读取 /2 使用的 proof-obligations.v2.json,先因 proofRegistryVersion=2026-07-15.v3 被 /1 validator 拒绝;改读旧数据但继续套新版 schema,又因新增 interactionOptionalRules 必填字段被拒。根因不是测试夹具,而是数据版本与 schema 版本没有成对绑定,生产路径会在 Writer 首条消息前统一早失败。当前 /1 编排明确固定为 proof-obligations.2026-07-14.v2.json 与 proof-obligation-registry.2026-07-14.v2.schema.json;/2 继续使用滚动 canonical 注册表和新版 schema。冻结对验证与一次修复回路回归均通过,后续迁移必须同时切 request、provenance、interaction binding、注册表和 schema,禁止只替换其中一个文件。
2026-07-17 的人工反馈坐实前述直链分叉:五个普通 URL 均不可玩,而此前“HTTP 200 + 注入 profile 的自动 Chromium”被错误地描述为可人工试玩。修复后五款重新 build/stage,并使用实际 /Applications/Google Chrome.app、390×844 视口、真实鼠标事件、完全不注入 profile 重跑。五款首击均只显示白色选中环;固定合法交换 (255,140)→(255,180) 后分数分别为 30/45/30/10/10,步数均 20→19;固定无效交换 (55,140)→(95,140) 后棋盘均恢复、分数保持 0。首次负例又发现 candy 早返回导致步数不扣,修复为无效事务同步扣步并在最后一步进入失败终态,复测同样为 20→19。正反截图保存在各 staged 目录的 evidence/direct-valid* 与 evidence/direct-invalid*。显式错误 profile 仍使 gem 帧停在 2→2,证明 runner 覆盖没有被默认值绕过。
直链修复复审又关闭三类测试器假阳。导航前 runner profile 现用不可写、不可配置的属性冻结,生成 bundle 顶层不能覆盖可信输入;默认 profile 仍只存在于编译后的 L1 entry。smokeBoot 请求 tapSequence 时把动作派发、状态读取和截图整体记为 actionEvidenceOk,任一步失败都令最终 ok=false,不再用 boot/frame 绿掩盖动作证据错误。Chrome 发现统一覆盖 macOS Chromium/Chrome、Linux /usr/bin、/opt 与 PATH,并检查可执行权限;每次运行使用独立临时 user-data 目录,捕获启动错误与 stderr,避免 SIGKILL 残留锁使后续 CDP 启动随机失败。非法坐标负例已经证明在 booted=true、framesAdvanced=true 时仍会正确返回动作证据失败。
入口和 Candy 修复改变了 artifact 字节,旧专项证据不再绑定当前交付物。五款各重跑一轮当前协议后,producer preflight、Actor 首尝试、双 tap、BoardIdentity、事件因果和专项门均通过,Judge 均按单交换证据保持 inconclusive/proof_missing。新 artifactHash 依次为 gem faa7de5944b36892bd98146e6ffe14a86cfaa19ecdc7e629e1597aa29d6f5e40、candy 6923c594cccb25e840c185dab9d86c9de9dcd254461bdf4cddd3edd2e6693f47、porcelain f5f21081060a87b998632921651bb24787a5477f8c6f086075ff964f17e4750c、fruit 5cda0962dabd2c22b3b612e30a0768bea7b59ea4fab25c001455aafb9334bdde、rune f977c1edc490ef05a42657276429be9d680cb8d1712877f086dd6a3d4ca4eda2;本次重签总成本 ¥0.56399。真实用户可见 Chrome 会话与终局/重玩仍未完成人工验收,因此 canonicalRuntimeEligible=false 不变。
截至 2026-07-17,gem、candy、porcelain、fruit、rune 五个真实生成样本经定向修复后,各完成一个 seed 的专项机械闭环,证明当前 producer preflight、Actor 双 tap、事件因果、BoardIdentity、单轮与多轮连锁事件门和 Judge 双槽可以在五种视觉主题上协同工作。它们仍不是生成器原始产出直接通过,也不是游戏内容金标;现统一登记为 harness_fixture。每轮只做一次交换,目标、通关、最终成绩、重玩和主观手感尚未验收;Judge 3.0.13 也未完成连续三轮建线和第四轮确认。下一道 harness 门是五款真实浏览器人工真玩并封存 Actor/Judge prompt_eval_gold 正反例。内容线已于 2026-07-27 另行签认主题驱动、内容完整的首款 game_content_gold,对象是《山海行纪》地图1纵切版,不把 Match-3 fixture 冒充内容金标,也不替代本段 harness 门。后者未闭合前不启动 fresh 25;完整总门、historical 11 和 production shadow 20 仍未完成,canonicalRuntimeEligible=false 保持不变。
同日的动作可读性整改把此前散落在五款游戏内的瞬时动画收敛为受保护能力 match3VisualTimeline。业务逻辑在第二次点击同步提交分数、步数、棋盘和事件,视觉层只读取交换前后盘面及逐轮快照,固定回放交换、命中停留、消除、下落补位、连锁间隔和稳定;无效交换固定回放前移与回滚。五款真实 Chromium filmstrip 的有效交换均在 0–940ms 内经过上述阶段,五个棋盘主体采样点互不相同;无效交换最终盘面等于原盘,成功事件为零。动画进行中的第三次真实点击没有改变棋盘、分数、步数或事件数,输入锁成立。Candy 还暴露并修复了重力阶段反转幸存棋子顺序的业务错误。当前证据只来自 harness_fixture 的 smoke filmstrip;本节前述 visualDrain、Match3VisualAudit/1、Match3RollInteractionAudit/2 和 SingleRollProof/3 尚未接入生产 v3 runner,不能据此宣称完整视觉证据闭环已上线。
2026-07-18 的专项复核指出“透明缩小”仍不构成消除特效。时间线因此升级到 1.1.0,可信 builder 为模板和五款 harness_fixture 冻结 canonical geometry 与六色 Match3EffectPalette/1;L3 看不到 renderEffects,host 在游戏绘制状态恢复后统一尾绘。每个真实 matched cell 在 clear 阶段产生确定性主题色亮核、白色底环加主题色扩散环,以及八枚带白色底光的外移碎片;effectId、碎片方向、paletteHash、geometryHash、effectViewHash 和主画布 receipt 都可由可信 probe 读取。五款真实 Chromium 的 clear 帧均报告三个 effectId、三个 core、三个 ring 和 24 shards,离开 clear 后 effect view 归零;无效交换全程为零。match_hold 中注入第三次真实点击前后,棋盘、分数、步数、事件、effect probe 与 receipt 均不变。Gem 的旧 juice.burst 会把引擎粒子错画到 HUD,已删除,避免普通粒子冒充标准消除反馈。当前只实现了受保护 effect view、host receipt 和 smoke filmstrip;生产 runner 侧的 Match3EffectAudit/1、独立 mask 栅格化及 InteractionAudit/2 绑定仍是待办,canonicalRuntimeEligible=false 不变。
Prompt eval 门已补四项治理硬约束:Actor 专项目标仍为至少 4/5,Judge A/B 必须各 6/6,不再由通用 80% 门误放;Judge Gate2 同时核对 decision、failureClass、义务状态与语义标签,不能只拼合法引用假绿;baseline 必须绑定 Prompt 正文 hash、fixture 快照、模型、seed 策略、PromptEvalAudit/2 与执行代码 identity;相同 exact request 须连续三轮满足 prompt_eval_gold 稳定门,第三轮只允许建 baseline 且不自批,第四轮同身份、同请求独立复跑达到单轮标准才能放行。Actor 以 prompt_eval_gold 正确性而不是具体等价动作做聚合;Judge A/B 各自三轮必须 18/18。自然语言原文只留审计,不进入稳定性键。
3.12 PromptEvalAudit/2 可重放审计包
现有 Prompt eval 台账只留 Prompt、inputs、labels 和源图的集合 hash,模型调用后只保存最终 message.content。Actor 真正收到的 ActorView/3、TargetSet、TargetGuide 和完整请求体在运行结束后无法重建;重试过程、provider 原始响应、renderer/parser 代码身份也没有进入基线。这使 Prompt、fixture、guide、候选集和模型输出的变量混在一起,后续只能看到翻转,无法证明翻转由谁造成。
PromptEvalAudit/2 只解决这个归因缺口。它保证某次请求的字节、图片、视觉候选和消费代码可核验,并能用封存响应离线重跑 parser 和 prompt_eval_gold 比对。它不承诺 provider 在稍后重发时返回同一结果;temperature=0 和固定 seed 只是请求参数,不是模型确定性证明。
每轮在现有 runs/raw/<runId>/ 下封存一个审计包:
runs/raw/<runId>/
├── run-manifest.json
├── prompt/
│ ├── body.txt
│ └── registry-entry.json
├── fixtures/
│ ├── inputs.jsonl
│ ├── labels.jsonl
│ └── fixture-manifest.json
├── code/
│ ├── code-manifest.json
│ └── files/
└── samples/
└── sample-0001-<evalKeyHash>/
├── sample-manifest.json
├── input.json
├── label.json
├── messages.json
├── images/
├── actor-targets/
├── attempts/
├── parser-result.json
└── normalized-result.json
run-manifest.json 固定记录 schemaVersion、runId、Prompt id/version/body hash、fixture 快照、model、seed 策略、Git HEAD 与 dirty 状态、code identity、有序 sample 引用、auditComplete、incompleteReasons 和整包 hash。code/files/ 只封存本轮实际消费的 Prompt、eval gate、renderer、parser bridge、resolver 和相关 schema;当工作区未提交时,只记 commit 不足以重放,必须同时封存这些文件的原始字节和 SHA-256。
sample-manifest.json 记录 evalKey、顺序、policy seed、input/label/messages 及图片引用,并按真实发生顺序引用每个 attempt。每次 attempt 保存实际请求体的字节数与 SHA-256、发起/结束时间、HTTP 状态、耗时、原始 provider 响应或脱敏错误、是否可重试以及退避时长。原始 response 必须先按字节落盘再解析,不能只保存 message.content;provider response id、实际 model、created、system fingerprint、finish reason 和 usage 另做结构化投影,缺失时显式为 null,不伪造。
Actor 样本的 actor-targets/ 必须完整保存 clean frame、VisualTargetSet/1、TargetGuide 和 guide manifest,并封住 cleanFrameHash → generator id/version/configHash → targetSetHash → guideHash → messagesHash → requestBodyHash 链。Judge 保存实际发给 provider 的归一图片及顺序,不只指向源图。label 不得进入 request body;审计包同时留 label 只为离线裁分和证明未泄题。
安全边界比内网凭据入仓特例更严。Authorization、API key、Bearer token、cookie、proxy authorization、带 userinfo/query/fragment 的 URL、凭据 hash 和环境变量值任何时候都不得落盘;请求头与响应头只能按固定白名单投影,异常文本在落盘前脱敏。Prompt、fixture、模型响应和图片仍是内容数据;repo 内审计包只允许已确认无个人信息、授权明确的内部 fixture。任意 imageDataUrl、用户上传素材或第三方受限内容必须转入受限存储;在保留期、删除和访问权限未明确前,不得持久化到 git。图片以独立二进制 blob 存放,人读 messages 用 hash 引用,避免在 manifest 和 JSONL 里重复 data URL;为字节重放保留的实际 request body 受单样本和单 run 体积上限约束,超限就令 auditComplete=false,不能更新 baseline。
写入时先在同文件系统的 .tmp-<runId> 目录完成全部文件,目录和文件权限分别为 0700/0600。每个文件原子写入并 fsync,manifest 最后写;逐文件重算 hash、fsync 目录后原子 rename 为最终 runId,最后才持锁 append 每日 JSONL 台账并 fsync。崩溃遗留的 tmp 只能隔离清理,不得当成有效 run。auditComplete=false、任一必需文件缺失、hash 不一致、响应截断或超限都不得形成真模型裁决或 baseline。
旧台账保持只读,没有 PromptEvalAudit/2 manifest 的运行固定标为 legacy-v1/auditComplete=false,不回写、不补造历史 Prompt、guide、request id 或其它不可恢复字段。/private/tmp 现存文件只能进独立 recovered-evidence 包,保存发现时的原始字节、SHA-256、size、stat 与来源路径。它们与旧 run 的关系分三级:历史台账已记同一 hash 才能称 cryptographically-bound;仅 TargetSet 或图片 hash 匹配而旧账没有 guide hash 时只能称 consistent-with;只有文件名或时间接近则是 unbound。恢复包不改写旧 JSONL,不进 baseline 身份。
实施差量保持四个切口:模型 client 返回包含所有 attempt 的结构化结果,不再返回丢信息的 tuple;消息构造器同时返回实际多模态消息和 materialization manifest,Actor 路径把 TargetSet/guide 从临时目录提交给审计写入器;主流程先封口 run manifest,再写台账和 baseline;baseline 身份新增 audit/code identity,只接受 PromptEvalAudit/2 + auditComplete=true。第一版不建通用审计平台、不做 provider 输出确定性保证、不把用户内容带入 git、不回填旧账未知字段,也不用审计包替代生产 playtest/3 证据链。
验收时必须证明:使用唯一 sentinel API key 运行后递归扫描整包零命中;封存制品能重建与发送前 SHA-256 一致的请求体;Actor 的 source/TargetSet/guide/messages/request 链可逐段复算;封存 response 能离线重放出相同 parser、normalized 和 gold 结果;500 → timeout → success 三次 attempt 全部留痕;任一文件被改、缺失、超限或写入中崩溃都不能留下可用基线;两进程并发不串目录或 JSONL;旧账和恢复包的证据等级不能被升格。
3.13 参照资产双身份与生产 hash 门
ReferenceAssetRecord/1 和 ReferenceAssetRegistry/1 保持冻结,只服务既有证据与旧消费者;严格 schema 不原地加字段。生产可信消费升级为 /2,同时表达运行制品和生成输入两个不同对象。assetRef 只保留资产根的人读与审计定位,不再授权 Writer 直接读取活目录;artifactRef/artifactHash 绑定被签认和浏览器验收的唯一运行制品;consumptionManifestRef/consumptionManifestHash 绑定一份确定性清单,清单逐项列出 Writer 真正可见文件的仓根相对路径、原始字节 SHA-256 与大小。以《山海行纪》为例,运行制品仍是 dist/shanhai-bundle.js,当前 bundle hash 不变;消费清单只纳入已批准的源文件、内容表与设计输入,不把 evidence、临时输出或整个活目录自动纳入。
消费门从可信发布配置取得 registry 文件的预期 SHA-256、消费策略版本和 verifier 版本,不能从请求、当前工作目录或调用方路径推导。消费策略按生产路由固定 recordId + role + consumerRef;请求中的 referenceAssetRecordIds 与 consumerRef 只能作为一致性声明,缺失、增删或不匹配都不能关闭生产门。空声明旧路径只允许显式的 legacy shadow/frozen 运行,不得进入 live 生成。Registry 必须先过 /2 schema、recordId 唯一性、生命周期和消费策略对账,再处理具体记录;active 记录缺任一双身份字段都拒绝,曾经 active 后 retired 的记录永久保留原双身份与验证证据。
首个策略固定为 survivor-gold-v1,只绑定 gac-shanhai-xingji + game_content_gold + generation-runtime@reference-assets/2。当前 cheap 可信路由只有 narrative、TRPG、heritage、puzzle 与 sim-business,没有 survivor 路由;这五类不得自动套用《山海行纪》。CLI 与 Service 只提供受信 policyId 入口和冻结预检,在 survivor 模板、路由及其生产调用方另行批准前,survivor-gold-v1 不进入 live 自动选择,也不宣称已有生产流量。当前 frozen/manual 入口由可信调用方显式选择策略,不接收或猜测当前品类路由;未传 policyId 的现有五类路径保持原行为,未知或禁用的 policyId 必须在 Writer 前拒绝。
路径读取复用 §3.1 的受信快照边界:先锚定可信仓根目录描述符,再逐级以 openat + O_NOFOLLOW 打开;最终对象经 fstat 确认为普通文件,从同一文件描述符流式计算原始字节 SHA-256,读前后复核 device、inode、size、mtime 与 ctime。运行制品、消费清单及清单中的每个文件都走同一规则。生产 loader 不信 Registry/2 中登记的 artifactHash 自报正确:它从磁盘受信快照读取 artifactRef 的 bundle,现场复算 observedArtifactHash 并与登记值比较;消费清单原始字节和每个 entry 也在同一边界现场复算并分别对账登记 hash。清单不超过 1 MiB 和 512 项,单个被读文件不超过 16 MiB,单记录快照不超过 64 MiB,单次多记录消费合计不超过 128 MiB;稀疏文件按逻辑大小计预算。校验后的消费文件字节进入本次运行的只读内存快照;Writer 的 read 工具只访问这份已经验证的内存快照,绝不重新按 assetRef 或清单路径读取磁盘。这样 hash 对象与实际影响生成的字节处在同一个信任边界,检查后替换、读中改写、祖先 symlink、FIFO、socket、device、目录和超大或稀疏文件均不能绕过。
flowchart LR
A["可信发布配置\nregistry hash + policy"] --> B["验证 Registry/2 与固定消费策略"]
B --> C{"active / role / consumerRef / designRef"}
C -->|不成立| X["fail-closed"]
C -->|成立| D["原子读取运行制品\n核 artifactHash"]
D --> E["原子读取消费清单\n核 manifest hash"]
E --> F["逐项原子读取并核文件 hash"]
F --> G["形成只读内存快照 + 验证回执"]
G --> H["Writer 只读快照"]
生成入口与验收侧各自执行验证并产生 ReferenceAssetVerificationReceipt/1。回执冻结 registry 版本与实测 hash、策略与 verifier 版本、recordId、role、consumerRef、运行制品 ref/登记 hash/实测 hash、消费清单 ref/登记 hash/实测 hash以及最终快照 hash;失败时只记录稳定错误码、recordId 和必要路径标识,不记录文件内容。验收 provenance 升版引用回执的 ref/hash,旧 /3 provenance 保持只读,不能补写字段伪升级。多记录消费采用全有或全无:任一记录失败,不形成 consumed 快照,不创建 Writer,也不进入玩法 repair。
截至 2026-07-28,这条路径已经接入生产代码的冻结入口。CLI 与 Service 只有在可信调用方显式传入 policyId 时才运行 loader,并把同一策略、只读快照和 generation receipts 传入 Writer 与验收;唯一一次 repair 沿父链保留同一策略和同一组 generation receipts,不重新预检换值。验收侧不信生成侧的“已验证”结论,而是使用生产内置的 release、Registry/2 与 policy 锚点独立复验,再把结果与 generation receipts 做 canonical 全等对账;成功后自产 canonical acceptance receipt,并由 acceptance-provenance/4 以精确的 receipt ref/hash 闭合。sealed 重入同样重验当前 manifest、receipt 和策略事实,不能绕过这道门。
消费清单使用 ReferenceAssetConsumptionManifest/1 canonical JSON:UTF-8 无 BOM、无尾随换行、对象键按 Unicode code point 升序、数组保持 schema 规定顺序、字符串按 JSON 标准转义且不转义非 ASCII。每条路径必须是 NFC 规范化的仓根相对 POSIX 路径,不允许空段、.、..、反斜杠或重复;entries 按路径 UTF-8 字节升序,重复检查在 NFC 规范化后执行。consumptionManifestHash 是 canonical JSON 原始字节的 SHA-256。最终快照 hash 采用域标签 reference-asset-consumption-snapshot/1\n,随后对每项依次写入 8 字节大端路径字节长度、路径 UTF-8 字节、8 字节大端内容长度和内容原始字节,再计算 SHA-256;不得用字符串拼接、换行归一化或十六进制文件 hash 替代原始内容。Python、Node 与后续 Java 消费者必须用同一组正反向量对账。
验证回执同时保存可信发布配置中的 expectedRegistryHash、磁盘实测 observedRegistryHash、消费策略 canonical 内容 hash、verifierVersion 与不含绝对路径的 trustedRootId。trustedRootId 是发布系统赋予仓根或镜像内容的逻辑身份,不从 cwd 文本生成。回执 schema 强制期望值与实测值分栏,缺字段、调换两者、篡改 policy hash 或用绝对路径冒充逻辑身份均无效。
稳定错误码固定为:可信策略缺失 reference_policy_missing,registry hash 不符或 schema/语义不合规 reference_registry_untrusted/reference_registry_invalid,路径非法或越界 reference_path_invalid/reference_path_escape,祖先或末级 symlink reference_symlink,对象缺失、非普通文件、不可读或超限 reference_missing/reference_not_regular/reference_unreadable/reference_oversize,读取期间变化 reference_changed_during_read,运行制品、清单或清单条目漂移 reference_artifact_hash_mismatch/reference_manifest_hash_mismatch/reference_entry_hash_mismatch,调用方一致性声明冲突 reference_declaration_mismatch。它们都属于不可由 Writer 修复的注册表、发布装配或 tester 错误;只有明确的瞬时 I/O 故障可由上层最多重试一次,hash、路径、schema、策略和缺件错误不可重试。
消费门不负责构建、下载或修复制品。签认流程先用确定性构建生成运行制品,再生成消费清单并计算两组 hash;发布清单把 /2 registry、消费策略、运行制品、清单及其列出的文件作为同一发布单元。切换顺序固定为:干净检出重建并复算 → 部署双身份制品与 Registry/2 → 用冻结模式预检 → 配置可信 registry/policy hash → 才允许 live 消费。当前只闭合了显式 policyId 下的 frozen/manual A+ 能力;没有 survivor 路由、自动选择、live 流量、R1 attestation、私钥签名、部署或生产切流,不能把冻结入口存在写成生产已开闸。
4 步骤计划
4.1 协议与证据层
新建 playtest/3 schema 与 validator,contract-first 增加 VisualTargetSet/1、ActorSelection/1、ActorView/3、完整 targetResolution、Judge 槽清单、JudgeConsensus/1 和 CostReservation/1。Match-3 差量再按 §3.3.2 增加 interaction registry/binding、Match3BoardProjection/1、Match3SwapSet/1、BoardIdentityCheck/1、ActorView/4、ActorSelection/2、actionGroup 状态账、puzzle.swap-committed/puzzle.match-formed payload schema 与 puzzle.match3-valid-swap proof registry,不能在旧 strict schema 上静默扩字段。义务注册表先增加 interactionOptionalRules,同时新建显式携带 interactionBinding=null | InteractionBinding/1 的 acceptance-request/2、acceptance-provenance/2 和 ProofObligationResolution/1 sidecar;内部包升级为带 sidecar ref/hash 的 SingleRollProof/2,SingleRollProof/1 与 request/provenance /1 一并冻结,禁止就地扩字段或自动升级。playtest/3 与 SingleRollFactV3 继续使用现有顶层形态,通过既有 proofPackageRef/hash 指向内部包,再由 /2 包的 ref/hash 闭包回读 sidecar。normalized 坐标动作、JudgePackage 与 proof obligation 保持现有形态,降低 CDP 和证据链改动面。现有 playtest/2 文件、validator 和 native/shadow 证据全部冻结;active v3_shadow/v3 + native 切新 runner 后只签发 playtest/3,旧证据只读、冻结、不可发布,也不得通过适配器升级成 accept。同步补 schema/校验器、正负样本、run 目录、兼容投影和成本预留边界。
4.2 Actor、runner 与双 Judge
先实现离屏 target proposer/renderer,让生产与 eval 对同一 PNG 和 generatorConfig 产出逐字一致的 TargetSet/guide。第一阶段只接 Prompt eval,不接生产 Actor:区域、lattice、空间降级三路必须使五个 Actor prompt_eval_gold 候选覆盖率 5/5,Actor selection schema 5/5、行为至少 4/5,并把 proposer 漏检、Actor 选错、resolver 错误分开计数。达到门槛后,core 增加严格 selection parser/resolver,CDP 只派发 resolver 产出的 normalized action;裸坐标不得自动回落。
Judge 侧先提取单槽 normalize 与纯函数 consensus,覆盖全部逐义务和全局矩阵;再在唯一 JudgePackage 封存后并行调用 A/B,增加原子预算预留和分槽审计。Python rollGuard 新增 judgeIndependent/judgeConsensus 检查,judge_semantic_conflict 固定归 inconclusive 且不可被游戏第二掷自动翻案。先拿 GAME OVER 和当前五个假阳做 consensus fixture,再跑两槽真 M3;两个槽各自 schema 6/6、行为 6/6 且 consensus 假阳 0 前,不接生产 shadow。
4.3 Match-3 专用求解
实施按四个小步推进。第一步先落 interaction registry、可信 binding 对账、Match3BoardProjection/1 与 Match3SwapSet/1 schema、canonical hash、匿名类别排序和纯规则 solver,用独立 pair oracle 对现有 prompt_eval_gold 矩阵复算十六组合法 pair;这一阶段不调用 Actor、不派发浏览器动作。第二步接入只读感知器与 overlay normalizer,只从 clean frame 和 lattice 逐格裁切并归一同类外观,先在 shadow 输出 projection、候选和退出原因,不改变现有 Actor 选择。第三步先补 proof registry 的 interactionOptionalRules、acceptance-request/2、acceptance-provenance/2、ProofObligationResolution/1 与四方 binding preflight,再 contract-first 增加 ActorView/4、ActorSelection/2、swap_pair parser、BoardIdentityCheck、同组双 tap/一次受限恢复状态机和完整 attempt/actionGroup 审计;同时把 puzzle.swap-committed、puzzle.match-formed payload schema 与 defaultRequired=false 的 puzzle.match3-valid-swap 写入事件和 proof registry,prompt_eval_gold 从 endpoint 升为 pair,旧 endpoint 分数只保留观察列。任何一步未过契约门,后续状态机不得开始。第四步在真实 Chrome 中用标准模板 fixture 执行两次 tap,核对 binding 提升→actionGroup→第二 actionId→两事件→post frame→两步 proof,并把原始 normalizer audit 的 ref/hash 与重建摘要封入 BoardIdentity。专项门与 canonical 绑定完成后只允许进入 enforce 候选评审;仍须完成正式 game_content_gold 签认、完整总门和三批基线,不能直接翻转生产开关。
感知器模式固定为 off / shadow / enforce。off 完全不生成投影;shadow 生成并审计,但现有 Actor 行为不受影响;enforce 只在标准规则、可信 lattice 和投影 resolved 时给 Actor 候选 pair。任何 schema 或 interaction binding 漂移、棋格不全、歧义、特殊块、动画遮挡、首 tap 后 BoardIdentityCheck 为 changed/indeterminate 或无候选都 fail-closed,不从历史候选、旧 endpoint 校准锚或模型猜测补齐。post-first frame/TargetSet hash 变化按 BoardIdentityCheck 记录和判断,不单独视为失败。专用视觉模型只能作为有预算的可插拔感知器,不能替换规则 solver。
视觉事务按 contract-first 另行落 visualTimelineCapability、Match3EffectPalette/1、Match3VisualTransaction/1、Match3EffectView/1、Match3EffectRenderReceipt/1、Match3VisualAudit/1、Match3EffectAudit/1、Match3FilmstripAnalyzer/1、InputLockProbe/1、Match3RollInteractionAudit/2 与 SingleRollProof/3。先用纯逻辑 fixture 验证事务冻结、pieceId 守恒、reference replay、七轮/5秒上限、阶段推进、确定性 effect view、可信主画布 receipt、生命周期清空和输入锁,再给 _template-puzzle 的标准 Match-3 profile 装配受保护时间线;五款 harness_fixture 只保留主题图标绘制,消除特效由 host 在主体 render 后统一合成。runner 在正式双 tap 后增加无 actionId 的 visualDrain、每轮 clear 相对采样和稳定帧 sidecar,specialty gate/finalPostguard 强制消费 VisualAudit 与 EffectAudit,业务 proof 仍引用原 action-2 post frame。能力 identity、palette/build 绑定、事务 hash、effect receipt/mask、filmstrip configHash 和稳定 Projection 任一无法闭合时不得进入 fresh 25;此外还须另行签认目标品类的 game_content_gold,专项 fixture 不得替代。
性能与成本在 shadow 期实测,不先写乐观数字。每局记录逐格裁切、特征归一、聚类、交换枚举和首 tap 复核的 CPU 墙钟、峰值内存与审计字节;本地求解不得增加模型调用。若升级专用视觉模型,必须先通过 CostReservation/1,并计入单掷 ¥1.5 和 parent 链总成本;超预算直接 inconclusive/board_perception_unresolved。缓存键绑定 sourceFrameHash、targetSetHash、latticeId 和 classifier/solver configHash,只复用完全相同输入,首 tap 后的新 frame 不得误用旧缓存。
4.4 二掷和一次修复
接入 requested/actual host seed 握手、policy seed、合并矩阵和 parentRun repair 次数。用第一掷 inconclusive 的操作失手正例验证第二掷可以凭新增硬证平反;用两掷冲突、tester_error 一次基础设施重试和一致真失败验证不会误修或无限 resume。同步拆除旧九门玩法 resume,只保留生成期 check/build 修复。
4.5 三路 shadow
CLI、Service create、modify 改调唯一 run_acceptance_v3,先开 v3_shadow。后端按明确字段投影读写,核对三个入口产生同形 playtest/3、同一 outcome、同一失败层和同一证据引用。shadow 新生产 run 不执行旧 runner,全部内测隔离并冻结自动发布;shadow 数据不得混入正式成功率。
4.6 mini-desktop 权威验收与切换
先收口 Actor/Judge Prompt 稳定门,并对 gem、candy、porcelain、fruit、rune 五个 harness_fixture 做真实浏览器人工真玩,封存 prompt_eval_gold 正例、已知坏例和自动结论分歧;同时由内容线按《游戏内容金标》完成 designIntent → realizationEvidence,签认至少一款目标品类 game_content_gold;W-GOLD-LIVE 再把两阶段 brief、fixture role、generation_exemplar recordId 和 ReferenceAssetRegistry/2 接入实际 cheap/tier2 prompt,完成双身份版本门、缺维度拒绝负例、真模型回归和消费记录对账。三条线任一未闭合都不启动 fresh 25。随后重跑完整总门,再按 fresh 25 → historical 11 → 独立 production shadow 20 的顺序执行三批基线。三条入口各完成至少一条真实浏览器 E2E,人工复核所有分歧、reject、rescued、inconclusive、tester_error 和不少于五条普通 accept;发现人工与自动结论不一致时先修验收器并从受影响批次重跑,不能边跑边修改口径。三批闸门、prompt_eval_gold 稳定门、live prompt 接线与 game_content_gold 参照均达标后才能决定是否把模式切到 v3,然后再做 Service create 和 modify 回归;任何一项未达均保持 shadow 和发布冻结。
4.7 参照资产生产版本门
先冻结 /1 契约和 registry 快照,新建 ReferenceAssetRecord/2、ReferenceAssetRegistry/2、消费清单、可信消费策略与验证回执契约;同步修订《游戏内容金标》SoT,明确运行制品、生成输入快照与资产根的分工。为首款内容金标生成确定性消费清单,保留当前 bundle hash,补齐消费清单 hash、survivor-gold-v1 冻结预检策略及干净检出重建证据。生产 loader 双读版本但只允许 /2 进入新门:旧 /1 继续服务冻结回放,代码回滚必须与旧 registry 成对恢复,不能让旧代码读取新 registry;survivor 路由落地前不把该策略自动接入当前五类 cheap 生成。
实现先以真实文件建立红灯矩阵,覆盖正常匹配、bundle 篡改、清单及条目篡改、缺失、路径越界、仓根/祖先/末级 symlink、检查后替换、读中截断或改写、目录/FIFO/socket/device、超大或稀疏文件、active 缺字段、retired 身份保留、工作目录变化、调用方声明冲突、空声明 live 降级、多记录中途失败原子性,以及未声明 legacy 与非 active 记录零磁盘 I/O。随后复用受信快照读取器,把双 hash、内存快照和验证回执接到生成入口与验收侧;最后修正“当前无 active 记录”的历史说明,重跑契约、acceptance、full gate、内容金标证据门与干净检出构建。该步骤只解锁可信消费前置条件,不执行 R1 私钥签名、部署或生产切流。
2026-07-28 落地状态:上述 /2 schema、真实清单、固定策略、受信 loader、CLI/Service 显式策略传递、repair 保持、验收独立复验、自产回执与 acceptance-provenance/4 已接线;生产路径会从磁盘受信快照复算 bundle、manifest 和每个 entry 的 hash,Writer 只消费已验证内存字节。该状态只说明冻结可信消费前置条件已经闭合,不改写 /1 frozen legacy,也不表示 survivor live 路由、自动选择、R1 签名、部署或生产切流已经发生。
5 验证方式
5.1 协议与因果证据
- accepted 的必需 proof obligation 完整率必须为 100%;每个
sequenceRefsstep 的动作、动作后帧和事件全部存在、严格有序且哈希匹配,flat refs 与其投影一致。 loopClosed必须指向品类闭环事件,不得从 Actor 或 Judge 的布尔值生成。- 非法动作两次重试期间,截图哈希和虚拟时间保持不变;第三次归
tester_error。 - tap/key/drag 精确推进 600ms,wait 只接受并推进 100–600ms;长过程拆成连续短 wait,注入 30 秒模型墙钟延迟不得改变游戏逻辑时间。
- 合法动作
timeAdvance.ok=true、requestedBudgetMs 等于动作预算且 plannedFrames=executedFrames;删字段、帧数不闭合、非法动作携带非 null timeAdvance 均被契约负例拦截。 - 每次 post 取证都发生在 CDP virtual-time budget 完成之后;无输入自动动画不能被标成输入响应。
- 真实输入只允许同一原生 Event 同步 handler 内的
ctx.event继承 actionId;Promise/timer/RAF、保存事件二次派发、直接_emit、外部或嵌套host.stepFrames/tap/do/state都必须无归因,嵌套调用返回后外层同步 handler 仍恢复原 action。 - wait 事件只有在对应 obligation step 的
allowedActionTypes显式包含 wait 时才能进入候选;它可证明定时业务结果,但永远不能写入firstPlay.firstFeedback。 - 两掷的 requested/actual game seed、policy seed、存储目录和 Actor session 均不同,且 requestedSeed=actualSeed。
- transcript 保存
(preSeq, postSeq]的完整game/*事件区间,动作前证据与动作后证据不混挂;插件日志不能单独满足业务义务。 - 每条新生产
game/*业务事件都符合game-event/1;payloadCanonical 解析后与 payload 语义等值,payloadHash 等于 payloadCanonical 原始 UTF-8 字节的 SHA-256,1e-7与1e-6跨语言回归必须通过;诊断日志不得进入业务事件通道。 - 注册表 payload 谓词仅运行白名单操作;缺 path、类型不符、序列倒序、跨 run 或跨 artifact 引用均 fail-closed。
- orderedSeries 必须覆盖同一 group 的完整 3–12 步,步骤 actionId/post frame 两两独立,summary/terminal 汇总逐项一致;sameValue 任一路径缺失或跨 step 值不同均不能形成候选。
- proofProfileId 必须由可信编排器在 Writer 前写入只读 request,且与可信 builder provenance manifest、runner 参数及三份 hash 一致;Writer/模型改 profile 和 parent 链漂移均 fail-closed。五模板真交互生产者对账必须覆盖各自 profile 的 100% 默认必需义务,每个 brief 可选提升至少有一条正例;缺一项即禁止切
v3。 /2active 参照资产必须同时具备运行制品与消费清单双身份;生产路由由可信策略派生固定记录和角色,调用方不能以空声明关闭门。运行制品、清单或清单条目任一磁盘字节改变而登记不变时,生成入口和验收侧都不得产生 consumed 快照或启动后续工作;Writer 只能读取已验证内存快照。/1、未声明 legacy shadow/frozen 与非 active 记录不进入 live 门,非 active 记录在生命周期检查后不得触碰其占位路径。- interactionBinding 只能作为
acceptance-request/2与acceptance-provenance/2的嵌套字段,由 Writer 前的可信编排器写入;平铺 interactionProfileId/registryVersion/bindingHash 的 request 或 playtest 字段必须被拒。verified 时 request、provenance、独立文件、runner 派生参数四方一致,并与 acceptanceRequestHash、BoardProjection、SwapSet、BoardIdentityCheck 和 actionGroup 逐段对账;Writer/Actor 改 profile、repair parent 链漂移和把非标准 puzzle 强挂 Match-3 profile 都归tester_error/profile_contract_error。 puzzle.match3-valid-swap必须保持 defaultRequired=false;absent 时 request/provenance 都显式 null,runner path/scalars 不传、binding 文件不存在,required 集与现行puzzle.match-board完全一致。verified 四方过门且命中match3.orthogonal-swap-v1时才提升。JSON null 文件、单边 null、absent 仍传 path/scalar、verified 缺文件、旧/1伪升级、brief 误提升、interaction rule 重复、跨 proof profile 引用和 repair 改 binding 的负例全部必须失败。- 新
/2强制ProofObligationResolution/1 + packageType=SingleRollProof/2;legacy/1只读旧 validator 与packageType=SingleRollProof,无 sidecar 且 publishFrozen。目录级 validator 必须分别复算 interactionBindingFileHash、语义 interactionBindingHash、sidecar 原始字节 hash 和 SingleRollProof/2 hash,再核对字符串数组 interactionRuleMatches、requiredObligationIds 与 evidence。内部 packageType 错配、两类 binding hash 混用、sidecar 缺失、规则顺序漂移、把 interaction rule 混入 briefRuleMatches、普通 puzzle 出现 interactionRuleMatches 或 JudgePackage 泄漏 binding 都必须失败。 - ActorView 的
objectiveProgress只能由 runner 从当前增量候选快照生成,必须标candidateOnly=true,不得带 event type/谓词/refs、Judge 结论或任何 pass/reject 字段。 - Actor/Judge prompt eval 除决策标签外,必须经生产 parser 和候选引用边界复核;旧引用形态和不可消费 JSON 不得假绿。
- 同一 clean PNG 与
generatorConfig/1必须跨 run 产生逐字相同的 canonical targets 和 targetSetHash;guide manifest 只要求排除运行时 ref 后的 canonical 内容相同,且 source/target/guide 三组 ref/hash 绑定均可复算。source hash 漂移、坏 PNG、候选越界、ID 排序漂移、旧 targetSet、未知 ID、越界 cell、gesture 不支持和零长度 drag 全部 fail-closed。region 两边均不得小于 24px,候选数必须满足 region≤24、lattice≤4、顶层总数≤29;grid 不得计入 primary coverage。Actor 可见去重不得改写完整 targets、稳定 ID 或 targetSetHash,Python guide 与 Node catalog 对同一集合必须投影出同一 ID 序列;父容器与色块碎片不得覆盖紧框,g01线不得穿过 primary 区域,region ID 必须通过可读 leader 直接锚定 safePoint。 - Match-3 感知
prompt_eval_gold必须同时保存 source clean frame、可信 lattice、匿名8×8类别矩阵和合法 pair。正式样本要求逐格类别64/64、pair precision/recall 均为 100%,同输入跨进程重复结果逐字一致;label、源游戏状态和源码不得进入感知器输入。已校准的 firstEndpoint selection overlay 必须经版本化 normalizer 保持类别等价并得到 BoardIdentityCheck=equivalent;未知高亮、遮挡、特殊块、棋格缺失、近似图标和类别边界扰动必须稳定返回 indeterminate,不能产出部分猜测。 - Match-3 规则测试必须覆盖正交相邻与异类限制、交换前已有三连排除、新三连必须包含交换端点、四连/五连最大段、十字交叉、同 pair 反向去重、稳定 candidateId/hash、无候选和多候选。现有真实矩阵必须与人工双审、独立 reference oracle 封存的十六组 pair 一致,并派生出二十二个兼容 endpoint;reference oracle 不得导入生产 solver、共享候选生成函数或在测试时由生产输出回填。篡改任一 cell class 后候选集和 hash 必须按规则变化。
- swap_pair 状态机必须覆盖同组两次 tap、第一下后的 BoardIdentityCheck、支持的 selection overlay、第二下错端点/重复端点/跨 pair/旧 candidateSet、post-first 新 TargetSet 的等价 lattice 解析、真实几何/类别变化、首 tap 后业务推进、第二下无响应和正常新三连。任何不匹配都不得派发第二下或形成成功;正常路径的两个原生 action 必须共享 actionGroupId,并各自保留 pre/post frame、事件区间和 timeAdvance。
- actionGroup 恢复测试必须覆盖 profile 无 selectionReset、预算不足、reset 产生交换事件、reset 后成功生成新 candidateSet、旧 candidateId 被拒、第二 actionGroup 再次 abort。每掷 actionGroup 上限固定为 2,第二次失败必须终止为
inconclusive/board_identity_unresolved,不能继续调用 Actor、感知器或推进虚拟时间。 - Match-3 生产者 fixture 必须在第二 tap 同步栈依次发出
puzzle.swap-committed与puzzle.match-formed,并由 runtime 自动附同一 secondActionId。pair、moveId、revision、runs、matchedCells/count 和 post frame 全部一致时,puzzle.match3-valid-swap才能 satisfied;异步事件、错误 actionId、事件倒序、moveId/pair 不同、matchedCount 不等、只有像素变化、只有 solver newRuns 或截图仍停在首 tap 选中态的负例全部不能满足义务。 visualTimelineCapability必须与 interaction registry、request/provenance/binding、runner 参数和宿主 probe 五方一致,同时保持 producer capability 身份逐字不变;能力缺失、错版、configHash 漂移、普通 puzzle 误注入和页面猴补 probe 都必须在 Actor 前失败。Match3VisualTransaction/1的 transactionHash、pieceId/kindToken、交换前后盘面、每轮 before/afterClear/gravityMoves/refills/afterFall 与最终盘面必须可由独立 reference replay 复算;runner 从初始64格独立建立 kindToken→BoardProjection classId 完整双射并封存到 VisualAudit,再与事件 moveId/runs/matchedCells 和稳定 BoardProjection 对账。篡改任一格、映射非一一、复用 refill ID、删除后复活、同类棋子交换 ID、遗漏轮次、重排下落、伪造补位或视觉事务与业务终盘分叉都不得通过。Match3RollInteractionAudit/2必须闭包引用 transaction、visual audit、effect audit、lock probe、filmstrip 与 settlement frame;effect audit 必须绑定Match3EffectPalette/1、artifact/build、effect view、host render receipt 与相对 clear 采样的 mask hash;SingleRollProof/3必须引用 Audit/2。旧 Audit/1 与 Proof/2 冻结,缺 sidecar、ref/hash 漂移、旧版静默加字段或未绑定视觉证据的包宣称动画完整都必须失败。- action-2 仍只推进 600ms;随后 visualDrain 无 actionId、无输入、无业务事件,结束前不得生成下一 ActorView 或调用 Judge。visualSettlementFrameRef、Match3VisualAudit 与 Match3EffectAudit 只进入 specialty gate/finalPostguard,不得替代 action post 或满足业务义务;visualDrain 中出现新事件、业务状态变化或超时必须失败。
- Match3FilmstripAnalyzer 必须排除 HUD、粒子、飘字和屏震,只从棋子主体证明 swap→clear→fall/refill→settle。早停在 hold/gap、只有粒子形成 distinct frame、阶段顺序颠倒、事件轮次多于视觉轮次、稳定帧与终盘不一致、八轮及以上或总长超过5秒均不能 accept;客观遮挡无法判断单列 inconclusive。
- InputLockProbe 使用同 artifact/seed 的独立零模型 control/probe,不污染正式两 action 账;300ms 第三 tap 前后 selected、board、score、moves、revision、events、pendingTerminal 与 transactionId 必须逐字不变,settle 后下一次输入恢复。只锁 UI 不锁业务、重复启动时间线或永久不解锁都必须失败。
- BoardProjection、SwapSet 和 solver 证明不得进入 ProofPackage/JudgePackage,也不得满足 obligation。删除隔离检查、把 candidate 存在或 endpoint 命中当成成功、把已有三连当新三连、只执行第一 tap 就结束的负例必须失败。
- Actor selection 中出现任何裸 x/y、任意比例或连续偏移字段必须被拒;非法 selection 不推进虚拟时间。合法 selection 解析后的 normalized tap/key/drag/wait 继续满足原时间与 isTrusted 因果边界。
- 合法 selection 连续无响应在生产黑盒中归
inconclusive/interaction_unresolved;只有 helper/hash/schema/越界/resolver 的确定性失败归 tester_error。eval 使用 gold mask/cell 时才允许细分 proposer、selection 和 resolver 错误。 - TargetSet、guide、proposalSource、score 与 safePoint 不得进入 ProofPackage/JudgePackage;删除该隔离检查或把候选选中当作义务证据的负例必须失败。
- Judge A/B 的 package/image hash 必须一致,client/session/policy seed/prompt artifact/output dir/raw ref 必须独立;任一独立性字段漂移归
tester_error/judge_independence_error。 - S/F/M/C 逐义务 16 组合、同状态 refs 漂移、accept+reject、reject 异 class/异签名、任一槽 parser/transport 错均有纯函数测试;只有双 accept 且全部 required satisfied 才可能 accept,只有双一致硬证 reject 才可能 reject。
- 二掷
inconclusive+reject、reject+inconclusive均必须保持 inconclusive;只有 failureClass、失败义务向量和 failureSignature 两掷一致才 gameplay reject/repair。单掷 deterministic contradiction 必须显式不可 repair。 - 并发前
CostReservation/1预算预留不足时不得发模型请求;request bytes 上界小于 provider prompt tokens、一个槽已计费而另一个失败、retry 追加预留不足、settlement 后差额未释放等情况均须 fail-closed,且不得用单槽结果降级。 - outcome 四态、二掷矩阵、一次基础设施重试、全 parent 链一次 repair、三路接口同形和未知 schema fail-closed 均有单元或契约测试。
5.2 prompt_eval_gold 校准
prompt_eval_gold 集不少于 20,其中稳定正例和已定标坏例各不少于 8。两个疑似假阴 heritage-r1、sim-business-r1 必须先经真人真浏览器定标,未定标前不进入真好通过率。历史 11 局的固定预期为:3 个 narrative 正例应保留;5 个旧假阳 trpg-r1/puzzle-r1/trpg-r2/heritage-r2/sim-business-r2 在没有新硬证时不得 accept;puzzle-r2 真代码 bug 应 reject;两个疑似假阴先真人定标。切换前必须满足:
- 已知坏例放行数为 0;当前五个无硬证假阳全部为
reject或inconclusive,不得 accept。 prompt_eval_gold假阳率为 0;真好样本在最多二掷后通过率不低于 90%。- 合法证据矛盾和无法证明好坏 100% 归
inconclusive;Actor/runner/Judge/schema/图像/环境异常 100% 归tester_error;两者都不进入 gameplay repair。 - accepted 中“结论与事件或截图矛盾”的数量为 0。
- Actor 的三个 tap
prompt_eval_goldprimary region/lattice coverage 必须为3/3,spatial fallback coverage 单列;五个prompt_eval_gold的 selection schema 为5/5、行为不低于4/5。shop、runner 必须通过生产 proposer→selection parser→resolver 全链;Match-3 必须通过 production proposer→BoardProjection→SwapSet→pair selection→同组双 tap→真实新三连结果全链。三者都记录候选规模、Actor top-1、resolver 命中和真实响应率,不能用人工硬编码 targetId、candidateId 或把 label 泄漏进请求。Match-3 的 endpoint 命中率只作历史观察,pair 与双 tap 结果才进入行为分。 - Judge A/B 两个槽分别达到 schema
6/6、行为6/6;GAME OVER反事实在多 policy seed 下 consensus 假阳为 0,任一槽分歧只能 inconclusive。 - 五个旧假阳既过旧证据 finalPostguard fixture,也在新 runner 下 fresh browser 重跑;不能只重解释旧 transcript。
5.3 波 3 新基线
五品类各五局共 25 个 distinct gid 全部在 mini-desktop 运行。每局同时记录四项:accepted(finalPostguard 封存的最终权威,包含首轮直接接受与 repair 后接受)、firstPassAccepted(完成最多二掷、尚未 writer repair 的终态)、rescuedByRoll、acceptedAfterRepair(只有真实发生 writer repair 且终态接受时为 true)。MVP 终态成功率按 accepted 计算,须至少 20/25 且任一品类不低于 3/5;acceptedAfterRepair 只统计修复救回率,绝不能拿它作成功率分子,否则会漏掉首轮直接成功。同时要求 firstPassAccepted >= 18/25、writer repair 启动率不超过 5/25、rescuedByRoll 不超过 5/25、单局验收成本不超过 ¥1.5、parentRun 全链总成本不超过便宜档既有 ¥15 硬地板。分子只计硬证完整、双 Judge consensus 接受且 finalPostguard 全绿的局。inconclusive/tester_error 单列,不得并入游戏失败,也不得从分母静默剔除。
CLI、Service create、modify 三路各至少一条权威 E2E 全绿。浏览器人工复核覆盖全部 reject、全部 rescued roll、全部 inconclusive/tester_error,以及至少五条普通 accept;人工结论与 v3 不一致时先修验收器并重跑,禁止用多数票掩盖。
5.4 生产分布 shadow 20
fresh 25 达标后,再用连续不少于 20 个真实生产 prompt 跑独立 v3_shadow,固定代码 commit、Chrome 版本、Actor/Judge 模型、prompt 版本、配置快照和人工标签。闸门为:accepted 的 proof 完整率 100%;确认假阳 0;accepted 与 problems/缺证/矛盾共存 0;tester_error < 5%、inconclusive < 10%;全部分歧、reject、rescued、inconclusive、tester_error 人工复核,普通 accept 至少抽 5。20 局口径下 <5% 意味着 tester_error 必须为 0,<10% 意味着 inconclusive 最多 1。未过任一项,继续保持发布冻结。
6 风险与回滚
最大的风险是把 proof obligation 做成新的私有判卷合约。控制办法是义务只描述用户可观察的业务结果,不规定游戏必须暴露某个变量名;事件采用统一 game/* 信封记录实际业务事实,画面仍是必要证据,Judge 负责核对二者是否一致。品类义务变更先改版本化注册表、schema、校验器和 prompt_eval_gold,不把一次事故继续叠成通用启发式。
视觉候选的最大风险是把 CV 启发式变成新私有判卷合约,或逼 Writer 为 proposer 画“更标准”的按钮。控制办法是候选只服务操作、永不进入 proof/Judge/repair,漏检与错框归 tester_error;prompt_eval_gold 保存可点击区域 mask/矩形或合法棋盘 cell pair,不保存脆弱 targetId。朴素 contour 编号首探只有 2/5,因此区域、lattice、空间降级和四段指标未过门前不接生产。
Actor 与两个 Judge 同为 M3 仍有同源盲区。双槽会话、检查顺序和输入投影隔离可以阻断已观察到的一好一坏组合,不能数学保证两槽不会同时犯同一错,因此 finalPostguard 与硬证仍拥有最终否决权,prompt_eval_gold 坏例零放行和真人抽玩仍是切换闸门。若目标生成、图像通道、任一 Judge 或 consensus 不稳定,outcome=tester_error 或 inconclusive,不降低证据标准。
Match-3 solver 的最大风险是把视觉聚类误称为确定性真相。确定性只表示同一输入按同一版本得到同一输出,不表示匿名类别一定正确;因此感知结果必须有逐格状态和置信、允许整体 abstain,并用 prompt_eval_gold 的完整类别矩阵与 pair 分别测 perception 与 solver。只要歧义可能改变候选集就退出,不能用“多数棋格看起来对”继续枚举。另一个风险是 solver 候选被误接进 proof;隔离负例必须保证 BoardProjection、SwapSet、candidateId 和 newRuns 永远停在 Actor/runner 审计层,最终成功仍只认真实双 tap 后的新画面、业务事件和义务证据。
条件提升的风险是把标准 Match-3 规则扩散到整个 puzzle.match-board。控制办法是专用义务保持 optional,只由已核验 interaction binding 提升;proof registry 与 interaction registry 双向对账,普通 /2 request/provenance 都显式写 null,runner 不创建 binding 文件。若 binding preflight、规则解析或版本兼容有任何异常,必须在 Actor 启动前归 tester_error/profile_contract_error。回滚 interaction enforce 时仍保留已绑定 Match-3 的义务提升,允许该 run 变成 inconclusive,但不能悄悄按普通 puzzle 放行;legacy /1 继续用旧 validator 与 SingleRollProof/1 只读且 publishFrozen,不能补写 null、sidecar 或伪造成 /2。
本地视觉求解的成本风险主要是高分辨率裁切、特征计算和审计文件膨胀,专用视觉模型还会增加推理成本。shadow 必须给出 CPU、内存、时延、缓存命中和审计体积的真实分布,再设 enforce 预算;超过预算或模型预留失败一律退出,不靠降低置信阈值换吞吐。缓存只服务同一 frozen frame,不能跨首 tap 复用,也不能让旧 candidateSet 越过新 TargetSet。
虚拟时间可能改变依赖真实墙钟的错误实现。v3 要求游戏逻辑走 runtime 时钟;检测到裸墙钟依赖时归机械或环境异常,先修产物或 runtime,不允许临时把模型延迟重新算进玩法。600ms 若需调整,必须通过 prompt_eval_gold 整批校准,不能按单局失败随意变动。
环境冷启动不得污染玩法时钟或 playableAtMs。runner 分别记录 Chrome 进程就绪、CDP 连接、browser-context 创建、导航提交、runtime boot 和游戏可交互六个时点,并为 process/CDP/context/navigation/boot 分别配置和记录 deadline,禁止用一个 30 秒总超时把冷启动假装成游戏启动慢。playableAtMs 只从导航提交后计时。mini-desktop 权威验收复用已就绪的 Chrome 进程,每掷创建隔离的新浏览器上下文;若 Chrome/CDP/context 自身超时,分别归 environment_chrome_startup / environment_cdp_connect / environment_context_create,不触发 writer repair。超时数值只能据分段日志校准,不得盲目拉长。
参照资产版本门的主要风险是运行制品与实际生成输入分叉、发布包缺件、可信策略未生效,或 /1 与 /2 错配。双身份记录、逐文件消费清单、只读内存快照和固定生产策略共同阻断前两类问题;发布时把代码、Registry/2、policy、bundle、清单和清单文件视为一个原子单元,先部署并冻结预检,后启用 live 策略。若新门导致现有声明无法消费,只能保持冻结、停用相应策略或整体回退代码与 registry 发布单元,再补齐原签认 hash 对应的制品;不得信任调用方自报 hash、按角色猜文件名、让 Writer 读活目录、运行时临时构建或放松 fd/symlink/越界检查。/1 注册表、/3 provenance 和既有消费证据保持只读,不能为兼容新门原地扩字段。
回滚分三层:单局可终止当前 run,证据保留;生产模式从 v3 退到 v3_shadow 并冻结自动放行;代码版本可整体回退新接线,但 playtest/2 与 playtest/3 已落证据均保持只读,不互相迁写或覆盖。Match-3 专用路径另有独立 off/shadow/enforce 开关,回滚时先从 enforce 降到 shadow,再在必要时关闭感知器;已封存的 interaction binding、义务提升结果、BoardProjection、SwapSet 与双 tap 动作账继续只读保留。关闭 solver 后不得恢复 endpoint-only 放行,也不得删除已绑定 Match-3 的 puzzle.match3-valid-swap required 状态;标准 Match-3 只能走诊断性通用 Actor并归 inconclusive,或等待经 prompt_eval_gold 校准的替代感知器。回滚后旧 runner 只能在 shadow 冻结态用于诊断,不能重新成为放量权威。
附 图清单与状态
| 图 | 位置 | 状态 | 事实源 |
|---|---|---|---|
| 生成线验收 v3 可信证据闭环 | 正文 §3.1 Mermaid | 现行 | 本档正文 |
主方案与生产者契约差量已按设计落地,本档继续留在在飞板承载 Prompt 校准、三批基线和 prompt_eval_gold 抽查。稳定结论只能在这些闸门完成后蒸馏进相关 SoT,然后再从在飞板移除本设计。