games.atmosphere.define

atmosphere.games

Schema Diff

+183 -148

From

CID
bafyreifg6gjn2um...
Indexed At
2026-07-17 14:46 UTC
View this version

To

CID
bafyreigaymudihd...
Indexed At
2026-07-20 03:53 UTC
View this version

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
}

Compare Other Versions

Lexicon Garden

@