games-development-ai/contracts/play-loop/playtest-evidence.schema.json
lili cbfd4d871b
Some checks failed
contract-gates / contract-gates (push) Has been cancelled
docs-gate / docs-gate (push) Has been cancelled
feat(acceptance): 闭合 playtest v3 与 A+ 可信消费链
固化 Match-3 生产者、视觉、音频与双 Judge 证据闭包。

将《山海行纪》r1.1 绑定新的不可变 release,并以生产预检现场核验 bundle、Registry/2 和 25 项 Writer 快照。

同步地图1平衡锁值、跨游戏回归修复、验收契约与 SoT 证据。
2026-07-28 20:16:13 -07:00

799 lines
27 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters

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

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://wanxiang.ai/contracts/play-loop/playtest-evidence.schema.json",
"title": "PlaytestEvidence",
"description": "便宜档生成验收 v3 的 playtest/2 权威证据契约。phase 与 outcome 正交;decision.accepted 永远等价 outcome=accept,而发布仅允许 active v3 accept。v3_shadow 即使终裁接受也必须 publishFrozen=true 且 compatibility.accepted/ok=false。Actor 只有动作权限,Judge 只读封存后的 JudgePackage,rollGuard 只产 rollOutcome,merge 只产 mergeCandidate,只有 finalPostguard 能写 decision 与唯一 compatibility 投影。",
"type": "object",
"required": [
"schemaVersion", "runId", "parentRunId", "gameId", "genre", "templateRoute", "proofProfileId",
"proofRegistryVersion", "taskBindingHash", "acceptanceRequestHash", "artifactHash", "briefHash",
"acceptanceMode", "evidenceMode", "phase", "environment", "floor", "actor", "actions", "events",
"briefRuleMatches", "proofObligations", "firstPlay", "rolls",
"merge", "judge", "repair", "costRmb"
],
"properties": {
"schemaVersion": {
"type": "string",
"const": "playtest/2"
},
"runId": {
"type": "string",
"minLength": 1
},
"parentRunId": {
"type": ["string", "null"]
},
"gameId": {
"type": "string",
"minLength": 1
},
"genre": {
"type": "string",
"enum": ["narrative", "trpg", "heritage", "puzzle", "sim-business"]
},
"templateRoute": {
"type": "string",
"pattern": "^_template-[a-z0-9-]+$"
},
"proofProfileId": {
"type": "string",
"pattern": "^[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*$"
},
"proofRegistryVersion": {
"type": "string",
"minLength": 1
},
"taskBindingHash": {
"$ref": "#/$defs/sha256"
},
"acceptanceRequestHash": {
"$ref": "#/$defs/sha256"
},
"artifactHash": {
"$ref": "#/$defs/sha256"
},
"briefHash": {
"$ref": "#/$defs/sha256"
},
"acceptanceMode": {
"type": "string",
"enum": ["v3_shadow", "v3", "historical_replay"]
},
"evidenceMode": {
"type": "string",
"enum": ["native", "legacy-adapted"]
},
"phase": {
"type": "string",
"enum": ["PRECHECK", "COLLECTING", "JUDGING", "DECIDED"]
},
"outcome": {
"$ref": "#/$defs/outcome"
},
"environment": {
"$ref": "#/$defs/environment"
},
"floor": {
"$ref": "#/$defs/floor"
},
"actor": {
"anyOf": [
{ "$ref": "#/$defs/actor" },
{ "type": "null" }
]
},
"actions": {
"type": "array",
"items": { "$ref": "#/$defs/actionRecord" }
},
"events": {
"type": "array",
"items": { "$ref": "game-event.schema.json" }
},
"briefRuleMatches": {
"type": "array",
"items": { "type": "string", "minLength": 1 }
},
"proofObligations": {
"type": "array",
"items": { "$ref": "#/$defs/proofObligation" }
},
"firstPlay": {
"$ref": "#/$defs/firstPlay"
},
"rolls": {
"type": "array",
"maxItems": 2,
"items": { "$ref": "#/$defs/roll" }
},
"merge": {
"anyOf": [
{ "$ref": "#/$defs/merge" },
{ "type": "null" }
]
},
"judge": {
"anyOf": [
{ "$ref": "#/$defs/judge" },
{ "type": "null" }
]
},
"repair": {
"$ref": "#/$defs/repair"
},
"costRmb": {
"type": "number",
"minimum": 0
},
"finalPostguard": {
"$ref": "#/$defs/finalPostguard"
},
"decision": {
"$ref": "#/$defs/decision"
},
"compatibility": {
"$ref": "#/$defs/compatibility"
}
},
"patternProperties": {
"^_": {}
},
"additionalProperties": false,
"allOf": [
{
"if": {
"properties": { "phase": { "const": "DECIDED" } },
"required": ["phase"]
},
"then": {
"required": ["outcome", "finalPostguard", "decision", "compatibility"]
},
"else": {
"not": {
"anyOf": [
{ "required": ["outcome"] },
{ "required": ["finalPostguard"] },
{ "required": ["decision"] },
{ "required": ["compatibility"] }
]
}
}
}
],
"$defs": {
"sha256": {
"type": "string",
"pattern": "^[0-9a-f]{64}$"
},
"outcome": {
"type": "string",
"enum": ["accept", "reject", "inconclusive", "tester_error"]
},
"environment": {
"type": "object",
"required": ["host", "chromeVersion", "viewport", "buildRef", "virtualTime"],
"properties": {
"host": { "type": "string", "minLength": 1 },
"chromeVersion": { "type": "string", "minLength": 1 },
"viewport": {
"type": "object",
"required": ["width", "height", "dpr"],
"properties": {
"width": { "const": 390 },
"height": { "const": 844 },
"dpr": { "const": 1 }
},
"additionalProperties": false
},
"buildRef": { "$ref": "#/$defs/sha256" },
"virtualTime": {
"type": "object",
"required": ["mode", "actionQuantumMs", "waitMinMs", "waitMaxMs"],
"properties": {
"mode": { "const": "cdp" },
"actionQuantumMs": { "const": 600 },
"waitMinMs": { "const": 100 },
"waitMaxMs": { "const": 3000 },
"rafFrameMs": { "type": "number", "minimum": 1 },
"bootBoundary": { "type": "object" }
},
"additionalProperties": false
},
"timings": {
"type": "object",
"required": [
"chromeProcessReadyWallMs", "cdpConnectedWallMs", "browserContextCreatedWallMs",
"navigationSubmittedWallMs", "runtimeBootedWallMs", "gameInteractiveWallMs"
],
"properties": {
"chromeProcessReadyWallMs": { "type": ["integer", "null"], "minimum": 0 },
"cdpConnectedWallMs": { "type": ["integer", "null"], "minimum": 0 },
"browserContextCreatedWallMs": { "type": ["integer", "null"], "minimum": 0 },
"navigationSubmittedWallMs": { "type": ["integer", "null"], "minimum": 0 },
"runtimeBootedWallMs": { "type": ["integer", "null"], "minimum": 0 },
"gameInteractiveWallMs": { "type": ["integer", "null"], "minimum": 0 }
},
"additionalProperties": false
}
},
"additionalProperties": false
},
"floor": {
"type": "object",
"required": ["pass", "gates"],
"properties": {
"pass": { "type": "boolean" },
"gates": {
"type": "object",
"required": ["A_boot", "B_uncaught", "C_frame", "D_render"],
"properties": {
"A_boot": { "$ref": "#/$defs/gateResult" },
"B_uncaught": { "$ref": "#/$defs/gateResult" },
"C_frame": { "$ref": "#/$defs/gateResult" },
"D_render": { "$ref": "#/$defs/gateResult" }
},
"additionalProperties": false
}
},
"additionalProperties": false
},
"gateResult": {
"type": "object",
"required": ["pass", "evidenceRef"],
"properties": {
"pass": { "type": "boolean" },
"evidenceRef": { "type": "string", "minLength": 1 },
"measurement": {}
},
"additionalProperties": false
},
"actor": {
"type": "object",
"required": [
"model", "apiClientId", "sessionId", "systemPromptVersion", "contextProjectionVersion",
"evidenceDir", "requestedGameSeed", "actualGameSeed", "policySeed"
],
"properties": {
"model": { "type": "string", "minLength": 1 },
"apiClientId": { "type": "string", "minLength": 1 },
"sessionId": { "type": "string", "minLength": 1 },
"systemPromptVersion": { "type": "string", "minLength": 1 },
"contextProjectionVersion": { "type": "string", "minLength": 1 },
"evidenceDir": { "type": "string", "minLength": 1 },
"requestedGameSeed": { "type": "integer", "minimum": 0 },
"actualGameSeed": { "type": "integer", "minimum": 0 },
"policySeed": { "type": "integer", "minimum": 0 }
},
"additionalProperties": false
},
"actionRecord": {
"type": "object",
"required": [
"actionId", "request", "normalized", "valid", "retryCount", "preFrameRef", "preEventSeq",
"dispatchReceipt", "virtualTimeBudgetMs", "timeAdvance", "postFrameRef", "postEventSeq", "protocolErrors"
],
"properties": {
"actionId": { "type": "string", "pattern": "^action-[1-9][0-9]*$" },
"request": {
"type": "object",
"required": ["raw", "parsed"],
"properties": {
"raw": { "type": "string" },
"parsed": {
"anyOf": [
{ "$ref": "#/$defs/action" },
{ "type": "null" }
]
}
},
"additionalProperties": false
},
"normalized": {
"anyOf": [
{ "$ref": "#/$defs/action" },
{ "type": "null" }
]
},
"valid": { "type": "boolean" },
"retryCount": { "type": "integer", "minimum": 0, "maximum": 2 },
"preFrameRef": { "$ref": "#/$defs/frameRef" },
"preEventSeq": { "type": "integer", "minimum": 0 },
"dispatchReceipt": {
"anyOf": [
{ "$ref": "#/$defs/dispatchReceipt" },
{ "type": "null" }
]
},
"virtualTimeBudgetMs": { "type": "integer", "minimum": 0, "maximum": 3000 },
"timeAdvance": {
"anyOf": [
{ "$ref": "#/$defs/timeAdvance" },
{ "type": "null" }
]
},
"postFrameRef": { "$ref": "#/$defs/frameRef" },
"postEventSeq": { "type": "integer", "minimum": 0 },
"protocolErrors": {
"type": "array",
"items": { "type": "string", "minLength": 1 }
}
},
"additionalProperties": false,
"allOf": [
{
"if": { "properties": { "valid": { "const": true } }, "required": ["valid"] },
"then": { "properties": { "timeAdvance": { "$ref": "#/$defs/timeAdvance" } } },
"else": { "properties": { "timeAdvance": { "type": "null" } } }
}
]
},
"action": {
"type": "object",
"required": ["type"],
"properties": {
"type": { "type": "string", "enum": ["tap", "key", "wait", "drag"] },
"x": { "type": "number", "minimum": 0 },
"y": { "type": "number", "minimum": 0 },
"key": { "type": "string", "minLength": 1 },
"ms": { "type": "integer", "minimum": 100, "maximum": 3000 },
"from": { "$ref": "#/$defs/point" },
"to": { "$ref": "#/$defs/point" }
},
"additionalProperties": false,
"allOf": [
{
"if": { "properties": { "type": { "const": "tap" } }, "required": ["type"] },
"then": { "required": ["x", "y"] }
},
{
"if": { "properties": { "type": { "const": "key" } }, "required": ["type"] },
"then": { "required": ["key"] }
},
{
"if": { "properties": { "type": { "const": "wait" } }, "required": ["type"] },
"then": { "required": ["ms"] }
},
{
"if": { "properties": { "type": { "const": "drag" } }, "required": ["type"] },
"then": { "required": ["from", "to", "ms"] }
}
]
},
"point": {
"type": "object",
"required": ["x", "y"],
"properties": {
"x": { "type": "number", "minimum": 0 },
"y": { "type": "number", "minimum": 0 }
},
"additionalProperties": false
},
"frameRef": {
"type": "object",
"required": ["path", "hash"],
"properties": {
"path": { "type": "string", "minLength": 1 },
"hash": { "$ref": "#/$defs/sha256" }
},
"additionalProperties": false
},
"dispatchReceipt": {
"type": "object",
"required": ["accepted", "wallTimeMs"],
"properties": {
"accepted": { "const": true },
"wallTimeMs": { "type": "integer", "minimum": 0 }
},
"additionalProperties": false
},
"timeAdvance": {
"type": "object",
"required": [
"requestedBudgetMs", "plannedFrames", "executedFrames", "callbacksRun", "carryMs", "ok"
],
"properties": {
"requestedBudgetMs": { "type": "integer", "minimum": 100, "maximum": 3000 },
"plannedFrames": { "type": "integer", "minimum": 0 },
"executedFrames": { "type": "integer", "minimum": 0 },
"callbacksRun": { "type": "integer", "minimum": 0 },
"carryMs": { "type": "number", "minimum": 0 },
"ok": { "const": true }
},
"additionalProperties": false
},
"proofObligation": {
"type": "object",
"required": [
"id", "required", "status", "sequenceRefs", "actionRefs", "postFrameRefs", "eventRefs",
"contradictions", "blockingProblems"
],
"properties": {
"id": { "type": "string", "pattern": "^[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*$" },
"required": { "type": "boolean" },
"status": {
"type": "string",
"enum": ["satisfied", "failed", "missing", "contradicted", "not-required"]
},
"sequenceRefs": {
"type": "array",
"items": { "$ref": "#/$defs/sequenceRef" }
},
"actionRefs": {
"type": "array",
"items": { "type": "string", "pattern": "^action-[1-9][0-9]*$" }
},
"postFrameRefs": {
"type": "array",
"items": { "type": "string", "minLength": 1 }
},
"eventRefs": {
"type": "array",
"items": { "type": "integer", "minimum": 1 }
},
"contradictions": {
"type": "array",
"items": { "type": "string", "minLength": 1 }
},
"blockingProblems": {
"type": "array",
"items": { "type": "string", "minLength": 1 }
}
},
"additionalProperties": false,
"allOf": [
{
"if": {
"properties": { "status": { "const": "satisfied" } },
"required": ["status"]
},
"then": {
"properties": {
"sequenceRefs": { "minItems": 1 },
"actionRefs": { "minItems": 1 },
"postFrameRefs": { "minItems": 1 },
"eventRefs": { "minItems": 1 },
"contradictions": { "maxItems": 0 },
"blockingProblems": { "maxItems": 0 }
}
}
}
]
},
"sequenceRef": {
"type": "object",
"required": ["stepId", "eventRef", "actionRef", "postFrameRef"],
"properties": {
"stepId": { "type": "string", "pattern": "^[a-z][a-z0-9-]*(?::[1-9][0-9]*)?$" },
"eventRef": { "type": "integer", "minimum": 1 },
"actionRef": { "type": "string", "pattern": "^action-[1-9][0-9]*$" },
"postFrameRef": { "type": "string", "minLength": 1 }
},
"additionalProperties": false
},
"firstPlay": {
"type": "object",
"required": [
"interactiveAtVirtualMs", "firstFeedbackAtVirtualMs", "loopClosedAtVirtualMs",
"loopClosed", "proofObligationRefs"
],
"properties": {
"interactiveAtVirtualMs": { "type": ["integer", "null"], "minimum": 0 },
"firstFeedbackAtVirtualMs": { "type": ["integer", "null"], "minimum": 0 },
"loopClosedAtVirtualMs": { "type": ["integer", "null"], "minimum": 0 },
"loopClosed": { "type": "boolean" },
"proofObligationRefs": {
"type": "array",
"items": { "type": "string", "pattern": "^[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*$" }
}
},
"additionalProperties": false
},
"roll": {
"type": "object",
"required": [
"rollId", "roll", "requestedGameSeed", "actualGameSeed", "policySeed", "actorSessionId",
"proofPackageRef", "judgePackageRef", "rollGuard", "rollOutcome", "errors", "costRmb"
],
"properties": {
"rollId": { "type": "string", "pattern": "^roll-[12]$" },
"roll": { "type": "integer", "minimum": 1, "maximum": 2 },
"requestedGameSeed": { "type": "integer", "minimum": 0 },
"actualGameSeed": { "type": "integer", "minimum": 0 },
"policySeed": { "type": "integer", "minimum": 0 },
"actorSessionId": { "type": "string", "minLength": 1 },
"proofPackageRef": { "type": "string", "minLength": 1 },
"judgePackageRef": { "type": ["string", "null"] },
"rollGuard": { "$ref": "#/$defs/guard" },
"rollOutcome": { "$ref": "#/$defs/outcome" },
"errors": {
"type": "array",
"items": { "type": "string", "minLength": 1 }
},
"costRmb": { "type": "number", "minimum": 0 }
},
"additionalProperties": false
},
"guard": {
"type": "object",
"required": ["pass", "checks", "blockingProblems", "contradictions", "reason"],
"properties": {
"pass": { "type": "boolean" },
"checks": {
"$ref": "#/$defs/guardChecks"
},
"blockingProblems": {
"type": "array",
"items": { "type": "string", "minLength": 1 }
},
"contradictions": {
"type": "array",
"items": { "type": "string", "minLength": 1 }
},
"reason": { "type": "string" }
},
"additionalProperties": false
},
"guardChecks": {
"type": "object",
"required": [
"floorPass", "requiredObligationsSatisfied", "referencesValid", "sameActionEvidence",
"noContradictions", "noBlockingProblems", "actorHealthy", "runnerHealthy", "judgeHealthy",
"judgeAccept"
],
"properties": {
"floorPass": { "type": "boolean" },
"requiredObligationsSatisfied": { "type": "boolean" },
"referencesValid": { "type": "boolean" },
"sameActionEvidence": { "type": "boolean" },
"noContradictions": { "type": "boolean" },
"noBlockingProblems": { "type": "boolean" },
"actorHealthy": { "type": "boolean" },
"runnerHealthy": { "type": "boolean" },
"judgeHealthy": { "type": "boolean" },
"judgeAccept": { "type": "boolean" }
},
"additionalProperties": false
},
"merge": {
"type": "object",
"required": ["triggered", "rollRefs", "mergeCandidate", "conflicts", "rescuedByRoll", "reason"],
"properties": {
"triggered": { "type": "boolean" },
"rollRefs": {
"type": "array",
"maxItems": 2,
"items": { "type": "string", "pattern": "^roll-[12]$" }
},
"mergeCandidate": { "$ref": "#/$defs/outcome" },
"conflicts": {
"type": "array",
"items": { "type": "string", "minLength": 1 }
},
"rescuedByRoll": { "type": ["integer", "null"], "minimum": 1, "maximum": 2 },
"reason": { "type": "string", "minLength": 1 }
},
"additionalProperties": false
},
"judge": {
"type": "object",
"required": [
"model", "apiClientId", "sessionId", "systemPromptVersion", "contextProjectionVersion",
"evidenceDir", "packageHash", "decision", "degraded", "obligationResults",
"contradictions", "blockingProblems"
],
"properties": {
"model": { "type": "string", "minLength": 1 },
"apiClientId": { "type": "string", "minLength": 1 },
"sessionId": { "type": "string", "minLength": 1 },
"systemPromptVersion": { "type": "string", "minLength": 1 },
"contextProjectionVersion": { "type": "string", "minLength": 1 },
"evidenceDir": { "type": "string", "minLength": 1 },
"packageHash": { "$ref": "#/$defs/sha256" },
"decision": { "$ref": "#/$defs/outcome" },
"degraded": { "type": "boolean" },
"obligationResults": {
"type": "array",
"items": {
"type": "object",
"required": ["id", "status", "sequenceRefs", "evidenceRefs"],
"properties": {
"id": { "type": "string", "pattern": "^[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*$" },
"status": { "type": "string", "enum": ["satisfied", "failed", "missing", "contradicted"] },
"sequenceRefs": {
"type": "array",
"items": { "$ref": "#/$defs/sequenceRef" }
},
"evidenceRefs": {
"type": "array",
"items": { "type": "string", "minLength": 1 }
}
},
"additionalProperties": false
}
},
"contradictions": {
"type": "array",
"items": { "type": "string", "minLength": 1 }
},
"blockingProblems": {
"type": "array",
"items": { "type": "string", "minLength": 1 }
}
},
"additionalProperties": false
},
"finalPostguard": {
"type": "object",
"required": [
"pass", "mergeCandidate", "checks", "blockingProblems", "contradictions",
"writeAuthority", "reason"
],
"properties": {
"pass": { "type": "boolean" },
"mergeCandidate": { "$ref": "#/$defs/outcome" },
"checks": { "$ref": "#/$defs/guardChecks" },
"blockingProblems": {
"type": "array",
"items": { "type": "string", "minLength": 1 }
},
"contradictions": {
"type": "array",
"items": { "type": "string", "minLength": 1 }
},
"writeAuthority": { "const": true },
"reason": { "type": "string" }
},
"additionalProperties": false
},
"repair": {
"type": "object",
"required": ["countAcrossParentChain", "eligible", "attempted", "reason"],
"properties": {
"countAcrossParentChain": { "type": "integer", "minimum": 0, "maximum": 1 },
"eligible": { "type": "boolean" },
"attempted": { "type": "boolean" },
"reason": { "type": "string" }
},
"additionalProperties": false
},
"decision": {
"type": "object",
"required": [
"outcome", "accepted", "shadowAccepted", "publishFrozen", "failure",
"repairCountAcrossParentChain", "repairEligible", "repairFeedback",
"rescuedByRoll", "costRmb", "parentChainCostRmb"
],
"properties": {
"outcome": { "$ref": "#/$defs/outcome" },
"accepted": { "type": "boolean" },
"shadowAccepted": { "type": ["boolean", "null"] },
"publishFrozen": { "type": "boolean" },
"failure": { "$ref": "#/$defs/decisionFailure" },
"repairCountAcrossParentChain": { "type": "integer", "minimum": 0, "maximum": 1 },
"repairEligible": { "type": "boolean" },
"repairFeedback": { "type": ["string", "null"] },
"rescuedByRoll": { "type": ["integer", "null"], "minimum": 1, "maximum": 2 },
"costRmb": { "type": "number", "minimum": 0 },
"parentChainCostRmb": { "type": "number", "minimum": 0 }
},
"additionalProperties": false
},
"decisionFailure": {
"type": "object",
"required": ["layer", "subtype", "reason"],
"properties": {
"layer": {
"type": "string",
"enum": ["none", "mechanical", "gameplay", "tester_degraded"]
},
"subtype": { "type": ["string", "null"] },
"reason": { "type": ["string", "null"] }
},
"additionalProperties": false
},
"compatibility": {
"type": "object",
"required": [
"accepted", "ok", "acceptanceVersion", "publishFrozen", "playtest", "judge",
"failureLayer", "failureReason", "trace"
],
"properties": {
"accepted": { "type": "boolean" },
"ok": { "type": "boolean" },
"acceptanceVersion": { "type": "string", "enum": ["v3_shadow", "v3", "historical_replay"] },
"publishFrozen": { "type": "boolean" },
"playtest": { "$ref": "#/$defs/compatibilityPlaytest" },
"judge": { "$ref": "#/$defs/compatibilityJudge" },
"failureLayer": { "$ref": "#/$defs/failureProjection" },
"failureReason": { "type": ["string", "null"] },
"trace": { "$ref": "#/$defs/compatibilityTrace" }
},
"additionalProperties": false
},
"compatibilityPlaytest": {
"type": "object",
"required": [
"schemaVersion", "outcome", "accepted", "rollCount", "rescuedByRoll", "costRmb",
"proofComplete", "firstPlay", "evidenceRefs"
],
"properties": {
"schemaVersion": { "const": "playtest/2" },
"outcome": { "$ref": "#/$defs/outcome" },
"accepted": { "type": "boolean" },
"rollCount": { "type": "integer", "minimum": 0, "maximum": 2 },
"rescuedByRoll": { "type": ["integer", "null"], "minimum": 1, "maximum": 2 },
"costRmb": { "type": "number", "minimum": 0 },
"proofComplete": { "type": "boolean" },
"firstPlay": { "$ref": "#/$defs/compatibilityFirstPlay" },
"evidenceRefs": { "$ref": "#/$defs/compatibilityEvidenceRefs" }
},
"additionalProperties": false
},
"compatibilityFirstPlay": {
"type": "object",
"required": ["playableAtMs", "firstFeedbackMs", "loopClosed", "proofRefs"],
"properties": {
"playableAtMs": { "type": ["integer", "null"], "minimum": 0 },
"firstFeedbackMs": { "type": ["integer", "null"], "minimum": 0 },
"loopClosed": { "type": "boolean" },
"proofRefs": {
"type": "array",
"items": { "type": "string", "pattern": "^[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*$" }
}
},
"additionalProperties": false
},
"compatibilityEvidenceRefs": {
"type": "object",
"required": ["actions", "frames", "events"],
"properties": {
"actions": { "type": "array", "items": { "type": "string", "pattern": "^action-[1-9][0-9]*$" } },
"frames": { "type": "array", "items": { "type": "string", "minLength": 1 } },
"events": { "type": "array", "items": { "type": "string", "pattern": "^[1-9][0-9]*$" } }
},
"additionalProperties": false
},
"compatibilityJudge": {
"type": "object",
"required": [
"ran", "verdict", "accepted", "degraded", "reason", "acceptanceVersion", "schemaVersion"
],
"properties": {
"ran": { "type": "boolean" },
"verdict": { "$ref": "#/$defs/outcome" },
"accepted": { "type": "boolean" },
"degraded": { "type": "boolean" },
"reason": { "type": ["string", "null"] },
"acceptanceVersion": { "type": "string", "enum": ["v3_shadow", "v3", "historical_replay"] },
"schemaVersion": { "const": "playtest/2" }
},
"additionalProperties": false
},
"failureProjection": {
"type": "object",
"required": ["layer", "reason", "failedGates"],
"properties": {
"layer": {
"type": "string",
"enum": ["none", "mechanical", "gameplay", "tester_degraded"]
},
"reason": { "type": ["string", "null"] },
"failedGates": {
"type": "array",
"items": { "type": "string", "minLength": 1 }
}
},
"additionalProperties": false
},
"compatibilityTrace": {
"type": "object",
"required": ["playtest", "gameplayJudge"],
"properties": {
"playtest": { "$ref": "#/$defs/compatibilityPlaytest" },
"gameplayJudge": { "$ref": "#/$defs/compatibilityJudge" }
},
"additionalProperties": false
}
}
}