games.atmosphere.define
Schema Diff
+183 -148
Compatibility Analysis
Breaking Changes Detected
38 breaking changes, 41 non-breaking changes.
Breaking Changes (38)
- RequiredEdgeAdded RequiredEdgeAdded { vertex_id: "games.atmosphere.define#recordUse", src: "games.atmosphere.define#recordUse", tgt: "games.atmosphere.define#recordUse.role", kind: "prop", name: Some("role") }
- RequiredEdgeAdded RequiredEdgeAdded { vertex_id: "games.atmosphere.define#recordUse", src: "games.atmosphere.define#recordUse", tgt: "games.atmosphere.define#recordUse.nsid", kind: "prop", name: Some("nsid") }
- RequiredEdgeRemoved RequiredEdgeRemoved { vertex_id: "games.atmosphere.define#lexiconRef", src: "games.atmosphere.define#lexiconRef", tgt: "games.atmosphere.define#lexiconRef.nsid", kind: "prop", name: Some("nsid") }
- RemovedVertex RemovedVertex { vertex_id: "games.atmosphere.define#field.valueBoolean" }
- RemovedVertex RemovedVertex { vertex_id: "games.atmosphere.define#field.valueInteger" }
- RemovedVertex RemovedVertex { vertex_id: "games.atmosphere.define#field.valueString" }
- RemovedVertex RemovedVertex { vertex_id: "games.atmosphere.define#filter.valueBoolean" }
- RemovedVertex RemovedVertex { vertex_id: "games.atmosphere.define#filter.valueInteger" }
- RemovedVertex RemovedVertex { vertex_id: "games.atmosphere.define#filter.valueString" }
- RemovedVertex RemovedVertex { vertex_id: "games.atmosphere.define#lexiconRef" }
- RemovedVertex RemovedVertex { vertex_id: "games.atmosphere.define#lexiconRef.acquire" }
- RemovedVertex RemovedVertex { vertex_id: "games.atmosphere.define#lexiconRef.nsid" }
- RemovedVertex RemovedVertex { vertex_id: "games.atmosphere.define#lexiconRef.purpose" }
- RemovedVertex RemovedVertex { vertex_id: "games.atmosphere.define#lexiconRef.verify" }
- RemovedVertex RemovedVertex { vertex_id: "games.atmosphere.define#rule.valueBoolean" }
- RemovedVertex RemovedVertex { vertex_id: "games.atmosphere.define#rule.valueInteger" }
- RemovedVertex RemovedVertex { vertex_id: "games.atmosphere.define#rule.valueString" }
- RemovedVertex RemovedVertex { vertex_id: "games.atmosphere.define:body.includes" }
- RemovedVertex RemovedVertex { vertex_id: "games.atmosphere.define:body.includes:items" }
- RemovedEdge RemovedEdge { src: "games.atmosphere.define#field", tgt: "games.atmosphere.define#field.valueBoolean", kind: "prop", name: Some("valueBoolean") }
- RemovedEdge RemovedEdge { src: "games.atmosphere.define#field", tgt: "games.atmosphere.define#field.valueInteger", kind: "prop", name: Some("valueInteger") }
- RemovedEdge RemovedEdge { src: "games.atmosphere.define#field", tgt: "games.atmosphere.define#field.valueString", kind: "prop", name: Some("valueString") }
- RemovedEdge RemovedEdge { src: "games.atmosphere.define#filter", tgt: "games.atmosphere.define#filter.valueBoolean", kind: "prop", name: Some("valueBoolean") }
- RemovedEdge RemovedEdge { src: "games.atmosphere.define#filter", tgt: "games.atmosphere.define#filter.valueInteger", kind: "prop", name: Some("valueInteger") }
- RemovedEdge RemovedEdge { src: "games.atmosphere.define#filter", tgt: "games.atmosphere.define#filter.valueString", kind: "prop", name: Some("valueString") }
- RemovedEdge RemovedEdge { src: "games.atmosphere.define#lexiconRef", tgt: "games.atmosphere.define#lexiconRef.acquire", kind: "prop", name: Some("acquire") }
- RemovedEdge RemovedEdge { src: "games.atmosphere.define#lexiconRef", tgt: "games.atmosphere.define#lexiconRef.purpose", kind: "prop", name: Some("purpose") }
- RemovedEdge RemovedEdge { src: "games.atmosphere.define#lexiconRef", tgt: "games.atmosphere.define#lexiconRef.verify", kind: "prop", name: Some("verify") }
- RemovedEdge RemovedEdge { src: "games.atmosphere.define#lexiconRef.verify", tgt: "games.atmosphere.define#rule", kind: "ref", name: None }
- RemovedEdge RemovedEdge { src: "games.atmosphere.define#rule", tgt: "games.atmosphere.define#rule.valueBoolean", kind: "prop", name: Some("valueBoolean") }
- RemovedEdge RemovedEdge { src: "games.atmosphere.define#rule", tgt: "games.atmosphere.define#rule.valueInteger", kind: "prop", name: Some("valueInteger") }
- RemovedEdge RemovedEdge { src: "games.atmosphere.define#rule", tgt: "games.atmosphere.define#rule.valueString", kind: "prop", name: Some("valueString") }
- RemovedEdge RemovedEdge { src: "games.atmosphere.define:body", tgt: "games.atmosphere.define:body.includes", kind: "prop", name: Some("includes") }
- RemovedEdge RemovedEdge { src: "games.atmosphere.define:body.includes", tgt: "games.atmosphere.define:body.includes:items", kind: "items", name: None }
- RemovedEdge RemovedEdge { src: "games.atmosphere.define:body.includes:items", tgt: "games.atmosphere.define#lexiconRef", kind: "ref", name: None }
- ConstraintTightened ConstraintTightened { vertex_id: "games.atmosphere.define#rule.op", sort: "knownValues", old_value: "[\"exists\",\"notExists\",\"isViewer\",\"eq\",\"neq\",\"gt\",\"gte\",\"lt\",\"lte\"]", new_value: "[\"exists\",\"notExists\",\"isPlayer\",\"eq\",\"neq\",\"gt\",\"gte\",\"lt\",\"lte\"]" }
- ConstraintTightened ConstraintTightened { vertex_id: "games.atmosphere.define#field.op", sort: "knownValues", old_value: "[\"exists\",\"notExists\",\"isViewer\",\"eq\",\"neq\",\"gt\",\"gte\",\"lt\",\"lte\"]", new_value: "[\"exists\",\"notExists\",\"isPlayer\",\"eq\",\"neq\",\"gt\",\"gte\",\"lt\",\"lte\"]" }
- ConstraintTightened ConstraintTightened { vertex_id: "games.atmosphere.define#filter.op", sort: "knownValues", old_value: "[\"exists\",\"notExists\",\"isViewer\",\"eq\",\"neq\",\"gt\",\"gte\",\"lt\",\"lte\"]", new_value: "[\"exists\",\"notExists\",\"isPlayer\",\"eq\",\"neq\",\"gt\",\"gte\",\"lt\",\"lte\"]" }
Non-Breaking Changes (41)
- AddedVertex AddedVertex { vertex_id: "games.atmosphere.define#field.value" }
- AddedVertex AddedVertex { vertex_id: "games.atmosphere.define#filter.value" }
- AddedVertex AddedVertex { vertex_id: "games.atmosphere.define#recordUse" }
- AddedVertex AddedVertex { vertex_id: "games.atmosphere.define#recordUse.acquire" }
- AddedVertex AddedVertex { vertex_id: "games.atmosphere.define#recordUse.authority" }
- AddedVertex AddedVertex { vertex_id: "games.atmosphere.define#recordUse.filters" }
- AddedVertex AddedVertex { vertex_id: "games.atmosphere.define#recordUse.filters:items" }
- AddedVertex AddedVertex { vertex_id: "games.atmosphere.define#recordUse.label" }
- AddedVertex AddedVertex { vertex_id: "games.atmosphere.define#recordUse.nsid" }
- AddedVertex AddedVertex { vertex_id: "games.atmosphere.define#recordUse.path" }
- AddedVertex AddedVertex { vertex_id: "games.atmosphere.define#recordUse.purpose" }
- AddedVertex AddedVertex { vertex_id: "games.atmosphere.define#recordUse.rkey" }
- AddedVertex AddedVertex { vertex_id: "games.atmosphere.define#recordUse.role" }
- AddedVertex AddedVertex { vertex_id: "games.atmosphere.define#recordUse.verify" }
- AddedVertex AddedVertex { vertex_id: "games.atmosphere.define#rule.value" }
- AddedVertex AddedVertex { vertex_id: "games.atmosphere.define#rule.verify" }
- AddedVertex AddedVertex { vertex_id: "games.atmosphere.define:body.legacyIds" }
- AddedVertex AddedVertex { vertex_id: "games.atmosphere.define:body.legacyIds:items" }
- AddedVertex AddedVertex { vertex_id: "games.atmosphere.define:body.uses" }
- AddedVertex AddedVertex { vertex_id: "games.atmosphere.define:body.uses:items" }
- AddedEdge AddedEdge { src: "games.atmosphere.define#field", tgt: "games.atmosphere.define#field.value", kind: "prop", name: Some("value") }
- AddedEdge AddedEdge { src: "games.atmosphere.define#filter", tgt: "games.atmosphere.define#filter.value", kind: "prop", name: Some("value") }
- AddedEdge AddedEdge { src: "games.atmosphere.define#recordUse", tgt: "games.atmosphere.define#recordUse.acquire", kind: "prop", name: Some("acquire") }
- AddedEdge AddedEdge { src: "games.atmosphere.define#recordUse", tgt: "games.atmosphere.define#recordUse.authority", kind: "prop", name: Some("authority") }
- AddedEdge AddedEdge { src: "games.atmosphere.define#recordUse", tgt: "games.atmosphere.define#recordUse.filters", kind: "prop", name: Some("filters") }
- AddedEdge AddedEdge { src: "games.atmosphere.define#recordUse", tgt: "games.atmosphere.define#recordUse.label", kind: "prop", name: Some("label") }
- AddedEdge AddedEdge { src: "games.atmosphere.define#recordUse", tgt: "games.atmosphere.define#recordUse.path", kind: "prop", name: Some("path") }
- AddedEdge AddedEdge { src: "games.atmosphere.define#recordUse", tgt: "games.atmosphere.define#recordUse.purpose", kind: "prop", name: Some("purpose") }
- AddedEdge AddedEdge { src: "games.atmosphere.define#recordUse", tgt: "games.atmosphere.define#recordUse.rkey", kind: "prop", name: Some("rkey") }
- AddedEdge AddedEdge { src: "games.atmosphere.define#recordUse", tgt: "games.atmosphere.define#recordUse.verify", kind: "prop", name: Some("verify") }
- AddedEdge AddedEdge { src: "games.atmosphere.define#recordUse.filters", tgt: "games.atmosphere.define#recordUse.filters:items", kind: "items", name: None }
- AddedEdge AddedEdge { src: "games.atmosphere.define#recordUse.filters:items", tgt: "games.atmosphere.define#filter", kind: "ref", name: None }
- AddedEdge AddedEdge { src: "games.atmosphere.define#recordUse.verify", tgt: "games.atmosphere.define#rule", kind: "ref", name: None }
- AddedEdge AddedEdge { src: "games.atmosphere.define#rule", tgt: "games.atmosphere.define#rule.value", kind: "prop", name: Some("value") }
- AddedEdge AddedEdge { src: "games.atmosphere.define#rule", tgt: "games.atmosphere.define#rule.verify", kind: "prop", name: Some("verify") }
- AddedEdge AddedEdge { src: "games.atmosphere.define#rule.verify", tgt: "games.atmosphere.define#rule", kind: "ref", name: None }
- AddedEdge AddedEdge { src: "games.atmosphere.define:body", tgt: "games.atmosphere.define:body.legacyIds", kind: "prop", name: Some("legacyIds") }
- AddedEdge AddedEdge { src: "games.atmosphere.define:body", tgt: "games.atmosphere.define:body.uses", kind: "prop", name: Some("uses") }
- AddedEdge AddedEdge { src: "games.atmosphere.define:body.legacyIds", tgt: "games.atmosphere.define:body.legacyIds:items", kind: "items", name: None }
- AddedEdge AddedEdge { src: "games.atmosphere.define:body.uses", tgt: "games.atmosphere.define:body.uses:items", kind: "items", name: None }
- AddedEdge AddedEdge { src: "games.atmosphere.define:body.uses:items", tgt: "games.atmosphere.define#recordUse", kind: "ref", name: None }
Migration Guidance
Removed Elements
RemovedVertex { vertex_id: "games.atmosphere.define#field.valueBoolean" }RemovedVertex { vertex_id: "games.atmosphere.define#field.valueInteger" }RemovedVertex { vertex_id: "games.atmosphere.define#field.valueString" }RemovedVertex { vertex_id: "games.atmosphere.define#filter.valueBoolean" }RemovedVertex { vertex_id: "games.atmosphere.define#filter.valueInteger" }RemovedVertex { vertex_id: "games.atmosphere.define#filter.valueString" }RemovedVertex { vertex_id: "games.atmosphere.define#lexiconRef" }RemovedVertex { vertex_id: "games.atmosphere.define#lexiconRef.acquire" }RemovedVertex { vertex_id: "games.atmosphere.define#lexiconRef.nsid" }RemovedVertex { vertex_id: "games.atmosphere.define#lexiconRef.purpose" }RemovedVertex { vertex_id: "games.atmosphere.define#lexiconRef.verify" }RemovedVertex { vertex_id: "games.atmosphere.define#rule.valueBoolean" }RemovedVertex { vertex_id: "games.atmosphere.define#rule.valueInteger" }RemovedVertex { vertex_id: "games.atmosphere.define#rule.valueString" }RemovedVertex { vertex_id: "games.atmosphere.define:body.includes" }RemovedVertex { vertex_id: "games.atmosphere.define:body.includes:items" }
Added Elements
AddedVertex { vertex_id: "games.atmosphere.define#field.value" }AddedVertex { vertex_id: "games.atmosphere.define#filter.value" }AddedVertex { vertex_id: "games.atmosphere.define#recordUse" }AddedVertex { vertex_id: "games.atmosphere.define#recordUse.acquire" }AddedVertex { vertex_id: "games.atmosphere.define#recordUse.authority" }AddedVertex { vertex_id: "games.atmosphere.define#recordUse.filters" }AddedVertex { vertex_id: "games.atmosphere.define#recordUse.filters:items" }AddedVertex { vertex_id: "games.atmosphere.define#recordUse.label" }AddedVertex { vertex_id: "games.atmosphere.define#recordUse.nsid" }AddedVertex { vertex_id: "games.atmosphere.define#recordUse.path" }AddedVertex { vertex_id: "games.atmosphere.define#recordUse.purpose" }AddedVertex { vertex_id: "games.atmosphere.define#recordUse.rkey" }AddedVertex { vertex_id: "games.atmosphere.define#recordUse.role" }AddedVertex { vertex_id: "games.atmosphere.define#recordUse.verify" }AddedVertex { vertex_id: "games.atmosphere.define#rule.value" }AddedVertex { vertex_id: "games.atmosphere.define#rule.verify" }AddedVertex { vertex_id: "games.atmosphere.define:body.legacyIds" }AddedVertex { vertex_id: "games.atmosphere.define:body.legacyIds:items" }AddedVertex { vertex_id: "games.atmosphere.define:body.uses" }AddedVertex { vertex_id: "games.atmosphere.define:body.uses:items" }
Constraint Changes
- ConstraintTightened ConstraintTightened { vertex_id: "games.atmosphere.define#field.op", sort: "knownValues", old_value: "[\"exists\",\"notExists\",\"isViewer\",\"eq\",\"neq\",\"gt\",\"gte\",\"lt\",\"lte\"]", new_value: "[\"exists\",\"notExists\",\"isPlayer\",\"eq\",\"neq\",\"gt\",\"gte\",\"lt\",\"lte\"]" }
- ConstraintTightened ConstraintTightened { vertex_id: "games.atmosphere.define#filter.op", sort: "knownValues", old_value: "[\"exists\",\"notExists\",\"isViewer\",\"eq\",\"neq\",\"gt\",\"gte\",\"lt\",\"lte\"]", new_value: "[\"exists\",\"notExists\",\"isPlayer\",\"eq\",\"neq\",\"gt\",\"gte\",\"lt\",\"lte\"]" }
- ConstraintTightened ConstraintTightened { vertex_id: "games.atmosphere.define#rule.op", sort: "knownValues", old_value: "[\"exists\",\"notExists\",\"isViewer\",\"eq\",\"neq\",\"gt\",\"gte\",\"lt\",\"lte\"]", new_value: "[\"exists\",\"notExists\",\"isPlayer\",\"eq\",\"neq\",\"gt\",\"gte\",\"lt\",\"lte\"]" }
Additional Notes
- Breaking: RequiredEdgeAdded { vertex_id: "games.atmosphere.define#recordUse", src: "games.atmosphere.define#recordUse", tgt: "games.atmosphere.define#recordUse.role", kind: "prop", name: Some("role") }
- Breaking: RequiredEdgeAdded { vertex_id: "games.atmosphere.define#recordUse", src: "games.atmosphere.define#recordUse", tgt: "games.atmosphere.define#recordUse.nsid", kind: "prop", name: Some("nsid") }
- Breaking: RequiredEdgeRemoved { vertex_id: "games.atmosphere.define#lexiconRef", src: "games.atmosphere.define#lexiconRef", tgt: "games.atmosphere.define#lexiconRef.nsid", kind: "prop", name: Some("nsid") }
- Breaking: RemovedEdge { src: "games.atmosphere.define#field", tgt: "games.atmosphere.define#field.valueBoolean", kind: "prop", name: Some("valueBoolean") }
- Breaking: RemovedEdge { src: "games.atmosphere.define#field", tgt: "games.atmosphere.define#field.valueInteger", kind: "prop", name: Some("valueInteger") }
- Breaking: RemovedEdge { src: "games.atmosphere.define#field", tgt: "games.atmosphere.define#field.valueString", kind: "prop", name: Some("valueString") }
- Breaking: RemovedEdge { src: "games.atmosphere.define#filter", tgt: "games.atmosphere.define#filter.valueBoolean", kind: "prop", name: Some("valueBoolean") }
- Breaking: RemovedEdge { src: "games.atmosphere.define#filter", tgt: "games.atmosphere.define#filter.valueInteger", kind: "prop", name: Some("valueInteger") }
- Breaking: RemovedEdge { src: "games.atmosphere.define#filter", tgt: "games.atmosphere.define#filter.valueString", kind: "prop", name: Some("valueString") }
- Breaking: RemovedEdge { src: "games.atmosphere.define#lexiconRef", tgt: "games.atmosphere.define#lexiconRef.acquire", kind: "prop", name: Some("acquire") }
- Breaking: RemovedEdge { src: "games.atmosphere.define#lexiconRef", tgt: "games.atmosphere.define#lexiconRef.purpose", kind: "prop", name: Some("purpose") }
- Breaking: RemovedEdge { src: "games.atmosphere.define#lexiconRef", tgt: "games.atmosphere.define#lexiconRef.verify", kind: "prop", name: Some("verify") }
- Breaking: RemovedEdge { src: "games.atmosphere.define#lexiconRef.verify", tgt: "games.atmosphere.define#rule", kind: "ref", name: None }
- Breaking: RemovedEdge { src: "games.atmosphere.define#rule", tgt: "games.atmosphere.define#rule.valueBoolean", kind: "prop", name: Some("valueBoolean") }
- Breaking: RemovedEdge { src: "games.atmosphere.define#rule", tgt: "games.atmosphere.define#rule.valueInteger", kind: "prop", name: Some("valueInteger") }
- Breaking: RemovedEdge { src: "games.atmosphere.define#rule", tgt: "games.atmosphere.define#rule.valueString", kind: "prop", name: Some("valueString") }
- Breaking: RemovedEdge { src: "games.atmosphere.define:body", tgt: "games.atmosphere.define:body.includes", kind: "prop", name: Some("includes") }
- Breaking: RemovedEdge { src: "games.atmosphere.define:body.includes", tgt: "games.atmosphere.define:body.includes:items", kind: "items", name: None }
- Breaking: RemovedEdge { src: "games.atmosphere.define:body.includes:items", tgt: "games.atmosphere.define#lexiconRef", kind: "ref", name: None }
- Non-breaking: AddedEdge { src: "games.atmosphere.define#field", tgt: "games.atmosphere.define#field.value", kind: "prop", name: Some("value") }
- Non-breaking: AddedEdge { src: "games.atmosphere.define#filter", tgt: "games.atmosphere.define#filter.value", kind: "prop", name: Some("value") }
- Non-breaking: AddedEdge { src: "games.atmosphere.define#recordUse", tgt: "games.atmosphere.define#recordUse.acquire", kind: "prop", name: Some("acquire") }
- Non-breaking: AddedEdge { src: "games.atmosphere.define#recordUse", tgt: "games.atmosphere.define#recordUse.authority", kind: "prop", name: Some("authority") }
- Non-breaking: AddedEdge { src: "games.atmosphere.define#recordUse", tgt: "games.atmosphere.define#recordUse.filters", kind: "prop", name: Some("filters") }
- Non-breaking: AddedEdge { src: "games.atmosphere.define#recordUse", tgt: "games.atmosphere.define#recordUse.label", kind: "prop", name: Some("label") }
- Non-breaking: AddedEdge { src: "games.atmosphere.define#recordUse", tgt: "games.atmosphere.define#recordUse.path", kind: "prop", name: Some("path") }
- Non-breaking: AddedEdge { src: "games.atmosphere.define#recordUse", tgt: "games.atmosphere.define#recordUse.purpose", kind: "prop", name: Some("purpose") }
- Non-breaking: AddedEdge { src: "games.atmosphere.define#recordUse", tgt: "games.atmosphere.define#recordUse.rkey", kind: "prop", name: Some("rkey") }
- Non-breaking: AddedEdge { src: "games.atmosphere.define#recordUse", tgt: "games.atmosphere.define#recordUse.verify", kind: "prop", name: Some("verify") }
- Non-breaking: AddedEdge { src: "games.atmosphere.define#recordUse.filters", tgt: "games.atmosphere.define#recordUse.filters:items", kind: "items", name: None }
- Non-breaking: AddedEdge { src: "games.atmosphere.define#recordUse.filters:items", tgt: "games.atmosphere.define#filter", kind: "ref", name: None }
- Non-breaking: AddedEdge { src: "games.atmosphere.define#recordUse.verify", tgt: "games.atmosphere.define#rule", kind: "ref", name: None }
- Non-breaking: AddedEdge { src: "games.atmosphere.define#rule", tgt: "games.atmosphere.define#rule.value", kind: "prop", name: Some("value") }
- Non-breaking: AddedEdge { src: "games.atmosphere.define#rule", tgt: "games.atmosphere.define#rule.verify", kind: "prop", name: Some("verify") }
- Non-breaking: AddedEdge { src: "games.atmosphere.define#rule.verify", tgt: "games.atmosphere.define#rule", kind: "ref", name: None }
- Non-breaking: AddedEdge { src: "games.atmosphere.define:body", tgt: "games.atmosphere.define:body.legacyIds", kind: "prop", name: Some("legacyIds") }
- Non-breaking: AddedEdge { src: "games.atmosphere.define:body", tgt: "games.atmosphere.define:body.uses", kind: "prop", name: Some("uses") }
- Non-breaking: AddedEdge { src: "games.atmosphere.define:body.legacyIds", tgt: "games.atmosphere.define:body.legacyIds:items", kind: "items", name: None }
- Non-breaking: AddedEdge { src: "games.atmosphere.define:body.uses", tgt: "games.atmosphere.define:body.uses:items", kind: "items", name: None }
- Non-breaking: AddedEdge { src: "games.atmosphere.define:body.uses:items", tgt: "games.atmosphere.define#recordUse", kind: "ref", name: None }
1
1
{
2
2
"id": "games.atmosphere.define",
3
3
"defs": {
4
4
"all": {
5
5
"type": "object",
6
6
"required": [
7
7
"check",
8
8
"rules"
9
9
],
10
10
"properties": {
11
11
"check": {
12
12
"type": "string",
13
13
"const": "all"
14
14
},
15
15
"label": {
16
16
"type": "string",
17
17
"maxLength": 120
18
18
},
19
19
"rules": {
20
20
"type": "array",
21
21
"items": {
22
22
"ref": "#rule",
23
23
"type": "ref"
24
24
},
25
25
"maxLength": 16,
26
26
"minLength": 1
27
27
},
28
28
"acquire": {
29
29
"type": "string",
30
30
"format": "uri"
31
31
}
32
32
},
33
-
"description": "Logical AND. Passes only when every sub-rule passes."
33
+
"description": "Passes only when every rule passes."
34
34
},
35
35
"any": {
36
36
"type": "object",
37
37
"required": [
38
38
"check",
39
39
"rules"
40
40
],
41
41
"properties": {
42
42
"check": {
43
43
"type": "string",
44
44
"const": "any"
45
45
},
46
46
"label": {
47
47
"type": "string",
48
48
"maxLength": 120
49
49
},
50
50
"rules": {
51
51
"type": "array",
52
52
"items": {
53
53
"ref": "#rule",
54
54
"type": "ref"
55
55
},
56
56
"maxLength": 16,
57
57
"minLength": 1
58
58
},
59
59
"acquire": {
60
60
"type": "string",
61
61
"format": "uri"
62
62
}
63
63
},
64
-
"description": "Logical OR. Passes when at least one sub-rule passes, e.g. 'holds a sheet in any of these systems'."
64
+
"description": "Passes when at least one rule passes."
65
65
},
66
66
"not": {
67
67
"type": "object",
68
68
"required": [
69
69
"check",
70
70
"rule"
71
71
],
72
72
"properties": {
73
73
"rule": {
74
74
"ref": "#rule",
75
75
"type": "ref"
76
76
},
77
77
"check": {
78
78
"type": "string",
79
79
"const": "not"
80
80
},
81
81
"label": {
82
82
"type": "string",
83
83
"maxLength": 120
84
84
}
85
85
},
86
-
"description": "Logical NOT. Passes only when the sub-rule fails. Use for exclusion gates: 'has not already claimed this reward'."
86
+
"description": "Passes only when the nested rule fails."
87
87
},
88
88
"main": {
89
89
"key": "any",
90
90
"type": "record",
91
91
"record": {
92
92
"type": "object",
93
93
"required": [
94
94
"name",
95
95
"url",
96
96
"publisher",
97
97
"category",
98
98
"createdAt"
99
99
],
100
100
"properties": {
101
101
"url": {
102
102
"type": "string",
103
103
"format": "uri",
104
-
"description": "URL at which the game is played, downloaded, or accessed. This is a launch location, not the record's identity."
104
+
"description": "Where to play, download, or access the game."
105
105
},
106
106
"icon": {
107
107
"type": "blob",
108
108
"accept": [
109
109
"image/png",
110
110
"image/webp"
111
111
],
112
112
"maxSize": 512000,
113
-
"description": "Square icon for compact display contexts. Recommended 256x256 px."
113
+
"description": "Square icon. 256x256 recommended."
114
114
},
115
115
"name": {
116
116
"type": "string",
117
117
"maxLength": 100,
118
-
"description": "Display name of the experience as shown in portal listings."
118
+
"description": "Display name."
119
119
},
120
120
"tags": {
121
121
"type": "array",
122
122
"items": {
123
123
"type": "string",
124
124
"maxLength": 32
125
125
},
126
126
"maxLength": 12,
127
-
"description": "Freeform tags for search and discovery (e.g. 'arcade', 'pixel art', 'multiplayer')."
127
+
"description": "Freeform search tags."
128
+
},
129
+
"uses": {
130
+
"type": "array",
131
+
"items": {
132
+
"ref": "#recordUse",
133
+
"type": "ref"
134
+
},
135
+
"maxLength": 32,
136
+
"description": "Other records this game reads or writes. Not required to play."
128
137
},
129
138
"cover": {
130
139
"type": "blob",
131
140
"accept": [
132
141
"image/png",
133
142
"image/jpeg",
134
143
"image/webp"
135
144
],
136
145
"maxSize": 4000000,
137
-
"description": "Primary cover image. Portals display this as the card thumbnail. Recommended ratio 16:9."
146
+
"description": "Card thumbnail image. 16:9 recommended."
138
147
},
139
148
"media": {
140
149
"type": "array",
141
150
"items": {
142
151
"ref": "#mediaItem",
143
152
"type": "ref"
144
153
},
145
154
"maxLength": 24,
146
-
"description": "Extended media gallery, screenshots, banners, key art, and posters a portal can show on a detail page. 'cover' and 'icon' above stay the primary card images; this is the deeper set, mirroring the rich galleries dedicated game catalogs keep."
155
+
"description": "Extra screenshots, banners, and key art."
147
156
},
148
157
"status": {
149
158
"type": "string",
150
-
"description": "Current availability. Known values: 'live', 'beta', 'coming' (announced but not yet playable), 'archived' (no longer available). Open set; portals may badge or filter on these.",
159
+
"description": "Current availability.",
151
160
"knownValues": [
152
161
"live",
153
162
"beta",
154
163
"coming",
155
164
"archived"
156
165
]
157
166
},
158
167
"catalog": {
159
168
"type": "array",
160
169
"items": {
161
170
"ref": "#catalogRef",
162
171
"type": "ref"
163
172
},
164
173
"maxLength": 8,
165
-
"description": "Optional links to records in other game catalogs that describe this same title, most often a Pentaract (games.gamesgamesgamesgames.game) entry. This is how a definition borrows rich metadata a dedicated catalog already maintains, genres, platforms, screenshots, release dates, ratings, instead of duplicating it here. Purely supplementary: evaluation never reads these, and the experience is complete without them. Cooperate, don't re-enter."
174
+
"description": "Links to matching entries in other game catalogs. Purely supplementary."
166
175
},
167
176
"tagline": {
168
177
"type": "string",
169
178
"maxLength": 200,
170
-
"description": "One-line summary shown beneath the title in card views."
179
+
"description": "One-line summary."
171
180
},
172
181
"category": {
173
182
"type": "string",
174
183
"maxLength": 30,
175
-
"description": "Broad type of experience, used for portal filtering and display. Known values: 'browser' (plays in a web browser), 'download' (downloaded and run locally), 'physical' (tabletop or in-person), 'other'. This is an open set, portals should tolerate values they do not recognise.",
184
+
"description": "Type of experience.",
176
185
"knownValues": [
177
186
"browser",
178
187
"download",
179
188
"physical",
180
189
"other"
181
190
]
182
191
},
183
-
"includes": {
184
-
"type": "array",
185
-
"items": {
186
-
"ref": "#lexiconRef",
187
-
"type": "ref"
188
-
},
189
-
"maxLength": 24,
190
-
"description": "Records this game can use when present but never needs in order to run. Portals may show these as optional interoperability, import, cosmetic, or bonus features. They never gate play."
191
-
},
192
192
"requires": {
193
193
"type": "array",
194
194
"items": {
195
195
"ref": "#rule",
196
196
"type": "ref"
197
197
},
198
198
"maxLength": 16,
199
-
"description": "Hard playability requirements. Every rule must pass before the game can be played as declared. Do not put recommendations, bonuses, or merely supported records here. Portals surface failures as actionable prompts using each rule's 'acquire' link."
199
+
"description": "Hard gates. Every rule must pass before a player can use this game."
200
200
},
201
201
"trailers": {
202
202
"type": "array",
203
203
"items": {
204
204
"ref": "#video",
205
205
"type": "ref"
206
206
},
207
207
"maxLength": 8,
208
-
"description": "Video trailers and gameplay clips. Hosted externally (YouTube, Vimeo, Twitch) or linked directly so portals can embed or link them."
208
+
"description": "Video trailers or gameplay clips."
209
209
},
210
210
"createdAt": {
211
211
"type": "string",
212
212
"format": "datetime"
213
213
},
214
214
"developer": {
215
215
"ref": "#party",
216
216
"type": "ref",
217
-
"description": "The studio or individual who built the experience. Prefer a DID when available so the developer is verifiable on the network."
217
+
"description": "The studio or person who made this."
218
218
},
219
+
"legacyIds": {
220
+
"type": "array",
221
+
"items": {
222
+
"type": "string",
223
+
"maxLength": 80
224
+
},
225
+
"maxLength": 12,
226
+
"description": "Old IDs used for this same game by other catalogs or tools."
227
+
},
219
228
"publisher": {
220
229
"type": "string",
221
230
"format": "at-uri",
222
-
"description": "Stable AT-URI identifying the account that publishes and maintains this definition, normally at:// followed by the publishing DID. It must name the same repository that contains this record; portals should reject a mismatch."
231
+
"description": "AT-URI of the repo that owns this record. Must match this record's own repo."
223
232
},
224
233
"updatedAt": {
225
234
"type": "string",
226
235
"format": "datetime"
227
236
},
228
237
"releasedAt": {
229
238
"type": "string",
230
239
"format": "datetime",
231
-
"description": "When this experience became publicly available."
240
+
"description": "When this became available."
232
241
},
233
242
"description": {
234
243
"type": "string",
235
244
"maxLength": 2000,
236
-
"description": "Full description of the experience. Plain text; portals may render line breaks."
245
+
"description": "Full description."
237
246
},
238
247
"statNamespace": {
239
248
"type": "string",
240
249
"maxLength": 80,
241
-
"description": "Collection NSID under which this experience writes player activity. Portals count unique DIDs holding records here to derive player counts, no telemetry required."
250
+
"description": "Deprecated. Use uses[] instead."
242
251
}
243
252
}
244
253
},
245
-
"description": "Published to the publisher's own repository, one record per game. Use a stable, readable record key and update that same record in place. The record's at:// URI is its canonical identity; 'url' is an access location and may change. A portal must not merge definitions solely because their URLs match."
254
+
"description": "One game definition per record, published in the developer's own repo. Keep the same rkey to update it in place."
246
255
},
247
256
"rule": {
248
257
"type": "object",
249
258
"required": [
250
259
"check"
251
260
],
252
261
"properties": {
253
262
"op": {
254
263
"type": "string",
255
-
"description": "For field: comparison operator.",
264
+
"description": "Comparison operator.",
256
265
"knownValues": [
257
266
"exists",
258
267
"notExists",
259
-
"isViewer",
268
+
"isPlayer",
260
269
"eq",
261
270
"neq",
262
271
"gt",
263
272
"gte",
264
273
"lt",
265
274
"lte"
266
275
]
267
276
},
268
277
"nsid": {
269
278
"type": "string",
270
279
"format": "nsid",
271
-
"description": "Collection read by record, field, matches, or vouch."
280
+
"description": "Collection to read."
272
281
},
273
282
"rkey": {
274
283
"type": "string",
275
284
"maxLength": 50,
276
-
"description": "For field: record key, default 'self'; 'any' scans the collection."
285
+
"description": "Record key. Defaults to 'self'; 'any' scans the collection."
277
286
},
278
287
"rule": {
279
288
"ref": "#rule",
280
289
"type": "ref",
281
-
"description": "For not: nested rule to negate."
290
+
"description": "Nested rule for not."
282
291
},
283
292
"check": {
284
293
"type": "string",
285
-
"description": "Rule discriminator. Known values are open for forward compatibility; an unknown value must not pass.",
294
+
"description": "Rule type.",
286
295
"knownValues": [
287
296
"record",
288
297
"field",
289
298
"matches",
290
299
"vouch",
291
300
"all",
292
301
"any",
293
302
"not"
294
303
]
295
304
},
296
305
"field": {
297
306
"type": "string",
298
307
"maxLength": 200,
299
-
"description": "For field: dot-path to test."
308
+
"description": "Dot-path to test."
300
309
},
301
310
"label": {
302
311
"type": "string",
303
312
"maxLength": 120,
304
-
"description": "Human-readable requirement."
313
+
"description": "Why this is required."
305
314
},
306
315
"rules": {
307
316
"type": "array",
308
317
"items": {
309
318
"ref": "#rule",
310
319
"type": "ref"
311
320
},
312
321
"maxLength": 16,
313
322
"minLength": 1,
314
-
"description": "For all or any: nested rules."
323
+
"description": "Nested rules for all/any."
315
324
},
325
+
"value": {
326
+
"type": "unknown",
327
+
"description": "Comparison value."
328
+
},
329
+
"verify": {
330
+
"ref": "#rule",
331
+
"type": "ref",
332
+
"description": "Additional proof that must also pass when this rule is used in requires[]."
333
+
},
316
334
"acquire": {
317
335
"type": "string",
318
336
"format": "uri",
319
-
"description": "URL where a player can fulfil this requirement."
337
+
"description": "Where to get this."
320
338
},
321
339
"filters": {
322
340
"type": "array",
323
341
"items": {
324
342
"ref": "#filter",
325
343
"type": "ref"
326
344
},
327
345
"maxLength": 8,
328
346
"minLength": 1,
329
-
"description": "For matches or vouch: conditions that must hold on one record."
347
+
"description": "Conditions for matches or vouch."
330
348
},
331
349
"authority": {
332
350
"type": "string",
333
351
"format": "did",
334
-
"description": "For vouch: stable DID of the record issuer."
335
-
},
336
-
"valueString": {
337
-
"type": "string",
338
-
"maxLength": 1000,
339
-
"description": "String comparison value."
340
-
},
341
-
"valueBoolean": {
342
-
"type": "boolean",
343
-
"description": "Boolean comparison value."
344
-
},
345
-
"valueInteger": {
346
-
"type": "integer",
347
-
"description": "Integer comparison value."
352
+
"description": "DID of the trusted issuer, for vouch."
348
353
}
349
354
},
350
-
"description": "One recursive playability rule, discriminated by 'check'. Lexicon does not permit a union as a top-level definition, so this object carries the fields used by all seven variants. Evaluators enforce each variant's required fields: record(check,nsid); field(check,nsid,field,op); matches(check,nsid,filters); vouch(check,authority,nsid); all/any(check,rules); not(check,rule). Unknown check values evaluate as unknown, never as pass."
355
+
"description": "One playability rule. 'check' selects the variant: record, field, matches, vouch, all, any, or not. A rule may include verify for an additional required proof. An unknown check must never pass."
351
356
},
352
357
"field": {
353
358
"type": "object",
354
359
"required": [
355
360
"check",
356
361
"nsid",
357
362
"field",
358
363
"op"
359
364
],
360
365
"properties": {
361
366
"op": {
362
367
"type": "string",
363
-
"description": "How to test the field. exists/notExists check presence; eq/neq/gt/gte/lt/lte compare to a value; isViewer matches the signed-in player by their account ID (DID) and takes no value.",
368
+
"description": "Comparison operator.",
364
369
"knownValues": [
365
370
"exists",
366
371
"notExists",
367
-
"isViewer",
372
+
"isPlayer",
368
373
"eq",
369
374
"neq",
370
375
"gt",
371
376
"gte",
372
377
"lt",
373
378
"lte"
374
379
]
375
380
},
376
381
"nsid": {
377
382
"type": "string",
378
383
"format": "nsid"
379
384
},
380
385
"rkey": {
381
386
"type": "string",
382
387
"maxLength": 50,
383
-
"description": "Record key. Defaults to 'self'. Use 'any' to pass if any record in the collection satisfies the condition."
388
+
"description": "Record key. Defaults to 'self'; 'any' scans the collection."
384
389
},
385
390
"check": {
386
391
"type": "string",
387
392
"const": "field"
388
393
},
389
394
"field": {
390
395
"type": "string",
391
396
"maxLength": 200,
392
-
"description": "Dot-path to the property to evaluate (e.g. 'score.total', 'level'). Array traversal is not supported."
397
+
"description": "Dot-path to the property to test."
393
398
},
394
399
"label": {
395
400
"type": "string",
396
401
"maxLength": 120
397
402
},
403
+
"value": {
404
+
"type": "unknown",
405
+
"description": "Comparison value."
406
+
},
398
407
"acquire": {
399
408
"type": "string",
400
409
"format": "uri"
401
-
},
402
-
"valueString": {
403
-
"type": "string",
404
-
"maxLength": 1000,
405
-
"description": "String comparison value. For value-taking operators, set exactly one of valueString, valueInteger, or valueBoolean."
406
-
},
407
-
"valueBoolean": {
408
-
"type": "boolean",
409
-
"description": "Boolean comparison value."
410
-
},
411
-
"valueInteger": {
412
-
"type": "integer",
413
-
"description": "Integer comparison value. Use for numeric gt/gte/lt/lte checks."
414
410
}
415
411
},
416
-
"description": "Fetches a record from the player's repository and tests one field. Covers required fields, score thresholds, flags, and enum matches."
412
+
"description": "Passes if a field on the player's record meets a condition."
417
413
},
418
414
"party": {
419
415
"type": "object",
420
416
"required": [
421
417
"name"
422
418
],
423
419
"properties": {
424
420
"did": {
425
421
"type": "string",
426
422
"format": "did",
427
-
"description": "AT Protocol DID of this entity's account, if they have one."
423
+
"description": "DID of this entity's account, if it has one."
428
424
},
429
425
"url": {
430
426
"type": "string",
431
427
"format": "uri",
432
-
"description": "Website for this entity."
428
+
"description": "Website."
433
429
},
434
430
"name": {
435
431
"type": "string",
436
432
"maxLength": 100,
437
-
"description": "Display name of the entity."
433
+
"description": "Display name."
438
434
}
439
435
},
440
-
"description": "A named entity (developer, publisher, studio) associated with the experience."
436
+
"description": "An entity associated with the experience, such as its developer."
441
437
},
442
438
"video": {
443
439
"type": "object",
444
440
"required": [
445
441
"title"
446
442
],
447
443
"properties": {
448
444
"url": {
449
445
"type": "string",
450
446
"format": "uri",
451
-
"description": "Full URL to the video, used when no platform/videoId is given."
447
+
"description": "Direct URL, used when no platform/videoId is given."
452
448
},
453
449
"title": {
454
450
"type": "string",
455
451
"maxLength": 120,
456
-
"description": "Label for the clip (e.g. 'Launch Trailer')."
452
+
"description": "Clip title."
457
453
},
458
454
"videoId": {
459
455
"type": "string",
460
456
"maxLength": 120,
461
-
"description": "Platform video id (e.g. a YouTube id). Combined with 'platform' to build an embed."
457
+
"description": "Platform video id."
462
458
},
463
459
"platform": {
464
460
"type": "string",
465
-
"description": "Where the video lives. 'direct' means the url points straight at a video file or page.",
461
+
"description": "Where the video lives.",
466
462
"knownValues": [
467
463
"youtube",
468
464
"vimeo",
469
465
"twitch",
470
466
"direct"
471
467
]
472
468
},
473
469
"thumbnail": {
474
470
"type": "blob",
475
471
"accept": [
476
472
"image/png",
477
473
"image/jpeg",
478
474
"image/webp"
479
475
],
480
476
"maxSize": 2000000,
481
-
"description": "Optional still frame shown before the video plays."
477
+
"description": "Still frame shown before playing."
482
478
}
483
479
},
484
-
"description": "A trailer or gameplay clip. Provide a platform + videoId (preferred, so portals embed natively) or a direct url."
480
+
"description": "A trailer or gameplay clip."
485
481
},
486
482
"vouch": {
487
483
"type": "object",
488
484
"required": [
489
485
"check",
490
486
"authority",
491
487
"nsid"
492
488
],
493
489
"properties": {
494
490
"nsid": {
495
491
"type": "string",
496
492
"format": "nsid",
497
-
"description": "The kind of record to look for in that account's repo (e.g. equipment.rpg.give)."
493
+
"description": "Collection to look for in the authority's repo."
498
494
},
499
495
"check": {
500
496
"type": "string",
501
497
"const": "vouch"
502
498
},
503
499
"label": {
504
500
"type": "string",
505
501
"maxLength": 120
506
502
},
507
503
"acquire": {
508
504
"type": "string",
509
505
"format": "uri"
510
506
},
511
507
"filters": {
512
508
"type": "array",
513
509
"items": {
514
510
"ref": "#filter",
515
511
"type": "ref"
516
512
},
517
513
"maxLength": 8,
518
-
"description": "Conditions the record must meet, written exactly like a matches rule. Put the 'isViewer' operator on the field that names the player (e.g. recipient) to require the record reference the signed-in player; add value conditions (e.g. item equals jet_pack) to pin a specific grant. With no filters, any record of this kind on the authority's repo passes."
514
+
"description": "Conditions the record must meet. Use 'isPlayer' to require it name the signed-in player."
519
515
},
520
516
"authority": {
521
517
"type": "string",
522
518
"format": "did",
523
-
"description": "Stable DID of the account that issues the record (for example an item provider, guild, or tournament organiser). Handles are not accepted because they are mutable. A player can never be their own authority."
519
+
"description": "DID of the account that issues the record."
524
520
}
525
521
},
526
-
"description": "Passes when a trusted account's repo holds a record that meets the given conditions, optionally one that references the signed-in player. Because the record lives on the issuer's repo, not the player's, it cannot be forged. Use it for item grants, awards, memberships, approvals, licences, or any record one account publishes about another. Example: 'games.protoimsg.app has an equipment.rpg.give whose recipient is this player and whose item is jet_pack.'"
522
+
"description": "Passes if a trusted authority's repo holds a matching record. Use for grants, awards, or approvals one account issues about another."
527
523
},
528
524
"filter": {
529
525
"type": "object",
530
526
"required": [
531
527
"field",
532
528
"op"
533
529
],
534
530
"properties": {
535
531
"op": {
536
532
"type": "string",
537
-
"description": "How to test the field. exists/notExists check presence; eq/neq/gt/gte/lt/lte compare to a value; isViewer matches the signed-in player by their account ID (DID) and takes no value.",
533
+
"description": "Comparison operator.",
538
534
"knownValues": [
539
535
"exists",
540
536
"notExists",
541
-
"isViewer",
537
+
"isPlayer",
542
538
"eq",
543
539
"neq",
544
540
"gt",
545
541
"gte",
546
542
"lt",
547
543
"lte"
548
544
]
549
545
},
550
546
"field": {
551
547
"type": "string",
552
548
"maxLength": 200,
553
549
"description": "Dot-path to the field."
554
550
},
555
-
"valueString": {
556
-
"type": "string",
557
-
"maxLength": 1000,
558
-
"description": "String comparison value. For value-taking operators, set exactly one typed value property."
559
-
},
560
-
"valueBoolean": {
561
-
"type": "boolean",
562
-
"description": "Boolean comparison value."
563
-
},
564
-
"valueInteger": {
565
-
"type": "integer",
566
-
"description": "Integer comparison value. Use for numeric gt/gte/lt/lte checks."
551
+
"value": {
552
+
"type": "unknown",
553
+
"description": "Comparison value."
567
554
}
568
555
},
569
-
"description": "A single condition on a record's contents, used by matches and vouch. Most operators compare the field to a value. The special 'isViewer' operator takes no value and passes when the field identifies the signed-in player by their account ID (DID). It accepts the DID directly or an at:// URI whose repo is the player, and never matches on a handle, since handles can change. This is how a static definition points at whoever is reading it."
556
+
"description": "One field condition, used by matches and vouch. 'isPlayer' passes when the field names the signed-in player."
570
557
},
571
558
"record": {
572
559
"type": "object",
573
560
"required": [
574
561
"check",
575
562
"nsid"
576
563
],
577
564
"properties": {
578
565
"nsid": {
579
566
"type": "string",
580
567
"format": "nsid",
581
-
"description": "Collection to check on the player's PDS (e.g. 'actor.rpg.sprite')."
568
+
"description": "Collection to check."
582
569
},
583
570
"check": {
584
571
"type": "string",
585
572
"const": "record"
586
573
},
587
574
"label": {
588
575
"type": "string",
589
576
"maxLength": 120,
590
-
"description": "Human-readable requirement shown when gated (e.g. 'An rpg.actor sprite')."
577
+
"description": "Why this is required."
591
578
},
592
579
"acquire": {
593
580
"type": "string",
594
581
"format": "uri",
595
-
"description": "URL to send players who fail, so they can fulfil the requirement."
582
+
"description": "Where to get this."
596
583
}
597
584
},
598
-
"description": "Passes if the player's PDS holds at least one record in the given collection. The simplest gate: 'does this person participate in this lexicon at all?'"
585
+
"description": "Passes if the player holds any record in this collection."
599
586
},
600
587
"matches": {
601
588
"type": "object",
602
589
"required": [
603
590
"check",
604
591
"nsid",
605
592
"filters"
606
593
],
607
594
"properties": {
608
595
"nsid": {
609
596
"type": "string",
610
597
"format": "nsid"
611
598
},
612
599
"check": {
613
600
"type": "string",
614
601
"const": "matches"
615
602
},
616
603
"label": {
617
604
"type": "string",
618
605
"maxLength": 120
619
606
},
620
607
"acquire": {
621
608
"type": "string",
622
609
"format": "uri"
623
610
},
624
611
"filters": {
625
612
"type": "array",
626
613
"items": {
627
614
"ref": "#filter",
628
615
"type": "ref"
629
616
},
630
617
"maxLength": 8,
631
618
"minLength": 1,
632
-
"description": "All filters must match on the same record (AND semantics within one record)."
619
+
"description": "All filters must match on the same record."
633
620
}
634
621
},
635
-
"description": "Scans the player's collection and passes if any single record satisfies all filters simultaneously. Use to find a record by content rather than by key, e.g. 'holds item X', 'has membership tier Y'."
622
+
"description": "Passes if one record satisfies all filters."
636
623
},
637
624
"mediaItem": {
638
625
"type": "object",
639
626
"required": [
640
627
"image"
641
628
],
642
629
"properties": {
643
630
"alt": {
644
631
"type": "string",
645
632
"maxLength": 300,
646
-
"description": "Accessibility caption describing the image."
633
+
"description": "Accessibility caption."
647
634
},
648
635
"type": {
649
636
"type": "string",
650
-
"description": "What kind of image this is, so portals can place it (e.g. 'banner' across the top, 'screenshot' in a gallery).",
637
+
"description": "Kind of image.",
651
638
"knownValues": [
652
639
"screenshot",
653
640
"banner",
654
641
"artwork",
655
642
"poster",
656
643
"background",
657
644
"logo",
658
645
"thumbnail"
659
646
]
660
647
},
661
648
"image": {
662
649
"type": "blob",
663
650
"accept": [
664
651
"image/png",
665
652
"image/jpeg",
666
653
"image/webp",
667
654
"image/gif"
668
655
],
669
656
"maxSize": 8000000,
670
-
"description": "The image blob, stored on the developer's PDS."
657
+
"description": "The image blob."
671
658
},
672
659
"width": {
673
660
"type": "integer",
674
-
"description": "Pixel width, if known, lets portals reserve layout space before the blob loads."
661
+
"description": "Pixel width, if known."
675
662
},
676
663
"height": {
677
664
"type": "integer",
678
665
"description": "Pixel height, if known."
679
666
}
680
667
},
681
-
"description": "One image in the experience's media gallery."
668
+
"description": "One image in the media gallery."
682
669
},
670
+
"recordUse": {
671
+
"type": "object",
672
+
"required": [
673
+
"role",
674
+
"nsid"
675
+
],
676
+
"properties": {
677
+
"nsid": {
678
+
"type": "string",
679
+
"format": "nsid",
680
+
"description": "Collection to read."
681
+
},
682
+
"path": {
683
+
"type": "string",
684
+
"maxLength": 200,
685
+
"description": "Dot-path to the relevant value inside the record."
686
+
},
687
+
"rkey": {
688
+
"type": "string",
689
+
"maxLength": 50,
690
+
"description": "Record key. Defaults to 'self'; 'any' scans the collection."
691
+
},
692
+
"role": {
693
+
"type": "string",
694
+
"description": "What this record is used for.",
695
+
"knownValues": [
696
+
"character",
697
+
"perk",
698
+
"cosmetic",
699
+
"interop",
700
+
"stats",
701
+
"activity",
702
+
"leaderboard",
703
+
"profile",
704
+
"session",
705
+
"inventory",
706
+
"other"
707
+
]
708
+
},
709
+
"label": {
710
+
"type": "string",
711
+
"maxLength": 120,
712
+
"description": "Short label for this use."
713
+
},
714
+
"verify": {
715
+
"ref": "#rule",
716
+
"type": "ref",
717
+
"description": "Optional rule confirming this use is genuine."
718
+
},
719
+
"acquire": {
720
+
"type": "string",
721
+
"format": "uri",
722
+
"description": "Where to create or manage this record."
723
+
},
724
+
"filters": {
725
+
"type": "array",
726
+
"items": {
727
+
"ref": "#filter",
728
+
"type": "ref"
729
+
},
730
+
"maxLength": 8,
731
+
"description": "Conditions to match, used with rkey 'any' or an authority."
732
+
},
733
+
"purpose": {
734
+
"type": "string",
735
+
"maxLength": 300,
736
+
"description": "Why this record matters."
737
+
},
738
+
"authority": {
739
+
"type": "string",
740
+
"format": "did",
741
+
"description": "DID of the repo holding this record, if not the player's own."
742
+
}
743
+
},
744
+
"description": "An optional record this game reads or writes. Not required to play; see requires[] for hard gates."
745
+
},
683
746
"catalogRef": {
684
747
"type": "object",
685
748
"required": [
686
749
"uri"
687
750
],
688
751
"properties": {
689
752
"uri": {
690
753
"type": "string",
691
754
"format": "at-uri",
692
-
"description": "AT-URI of the external catalog record (e.g. at://did:web:gamesgamesgamesgames.games/games.gamesgamesgamesgames.game/3mgjih2bzdp2l)."
755
+
"description": "AT-URI of the external catalog record."
693
756
},
694
757
"name": {
695
758
"type": "string",
696
759
"maxLength": 100,
697
-
"description": "Display name of the referenced entry, so portals can show it without resolving the record."
760
+
"description": "Display name of the referenced entry."
698
761
},
699
762
"borrow": {
700
763
"type": "array",
701
764
"items": {
702
765
"type": "string",
703
766
"knownValues": [
704
767
"media",
705
768
"trailers",
706
769
"genres",
707
770
"platforms",
708
771
"releases",
709
772
"ratings",
710
773
"description",
711
774
"summary"
712
775
]
713
776
},
714
777
"maxLength": 8,
715
-
"description": "Advisory hints naming which parts of the referenced record a portal may display alongside this experience (e.g. pull screenshots and genres from Pentaract rather than duplicating them here). Display guidance only, never affects eligibility."
778
+
"description": "Which parts of the referenced record a portal may show alongside this one."
716
779
},
717
780
"source": {
718
781
"type": "string",
719
782
"maxLength": 60,
720
-
"description": "Short label for the catalog this points at (e.g. 'pentaract')."
721
-
}
722
-
},
723
-
"description": "A pointer to a record in another catalog that already describes this title in depth, most usefully a games.gamesgamesgamesgames.game record on The Pentaract, which carries genres, platforms, release dates, age ratings, and a full media gallery. The definition stays self-contained (eligibility never depends on it); the reference simply lets a portal fetch that richer metadata and show it alongside, so we build on existing game databases instead of re-entering everything."
724
-
},
725
-
"lexiconRef": {
726
-
"type": "object",
727
-
"required": [
728
-
"nsid"
729
-
],
730
-
"properties": {
731
-
"nsid": {
732
-
"type": "string",
733
-
"format": "nsid"
734
-
},
735
-
"verify": {
736
-
"ref": "#rule",
737
-
"type": "ref",
738
-
"description": "Optional rule that detects or authenticates this feature, typically a player-record match or a vouch in an issuer's separate grant collection. Portals may badge the feature when it passes. It never gates access."
739
-
},
740
-
"acquire": {
741
-
"type": "string",
742
-
"format": "uri",
743
-
"description": "Optional URL where a player can obtain this record."
744
-
},
745
-
"purpose": {
746
-
"type": "string",
747
-
"maxLength": 200,
748
-
"description": "How this lexicon enriches the experience when present. Shown to players."
783
+
"description": "Short name of the catalog."
749
784
}
750
785
},
751
-
"description": "A record collection this game can use when present, never a requirement. 'nsid' names the optional player-facing record; 'verify' may inspect that record or a separate issuer-controlled grant collection."
786
+
"description": "A link to a matching entry in another game catalog. Purely supplementary; never affects eligibility."
752
787
}
753
788
},
754
789
"$type": "com.atproto.lexicon.schema",
755
790
"lexicon": 1,
756
-
"description": "An AT Protocol game definition: a publisher's self-contained declaration of a playable experience, its presentation, the records a player must hold to play, and records the game can optionally use. Evaluators resolve requirements through AT Protocol repository reads; no game server or central eligibility database is required."
791
+
"description": "A game definition: what it is, what a player needs to play it, and what records it uses."
757
792
}