{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://touchstonestandard.org/schemas/0.3/assessment-input.schema.json",
  "title": "Touchstone assessment input",
  "description": "Version 0.3: every damage type requires De-minimis, Minor, Moderate or Severe.",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "rubric": {
      "type": "string",
      "description": "Optional rubric pin as rubric_id@version, e.g. 'default@0.3'. A host resolves this pin; score(input, rubric) uses its explicit rubric argument and does not resolve or enforce this field. Retain the actual rubric artifact and result version for reproduction."
    },
    "subject": {
      "type": "object",
      "additionalProperties": false,
      "description": "OPTIONAL card identity, e.g. game 'pokemon', set 'Base Set', number '4', name 'Charizard'. Never scored: it affects no deduction, sub-score, or grade.",
      "properties": {
        "game": {
          "type": "string"
        },
        "set": {
          "type": "string"
        },
        "number": {
          "type": "string"
        },
        "name": {
          "type": "string"
        }
      }
    },
    "front": {
      "$ref": "#/$defs/face"
    },
    "back": {
      "$ref": "#/$defs/face"
    }
  },
  "$defs": {
    "severity": {
      "enum": [
        "de_minimis",
        "minor",
        "moderate",
        "severe"
      ],
      "description": "Common damage severity: De-minimis, Minor, Moderate, Severe. Type and measured extent remain separate."
    },
    "crease_severity": {
      "enum": [
        "de_minimis",
        "minor",
        "moderate",
        "severe"
      ],
      "description": "Common damage severity: De-minimis, Minor, Moderate, Severe. Type and measured extent remain separate."
    },
    "stain_severity": {
      "enum": [
        "de_minimis",
        "minor",
        "moderate",
        "severe"
      ],
      "description": "Common damage severity: De-minimis, Minor, Moderate, Severe. Type and measured extent remain separate."
    },
    "print_defect_severity": {
      "enum": [
        "de_minimis",
        "minor",
        "moderate",
        "severe"
      ],
      "description": "Common damage severity: De-minimis, Minor, Moderate, Severe. Type and measured extent remain separate."
    },
    "line_endpoint": {
      "type": "number",
      "minimum": 0,
      "maximum": 1,
      "description": "Line endpoint coordinate (normalized 0–1 from the top-left of the face, same semantics as x/y). An OPTIONAL paired x2/y2 turns a placed surface/crease/edge defect into a line segment — a presentational/derivation aid (e.g. a UI derives the size class from the drawn physical length), NEVER scored: the reference scorer validates the pair when present and the arithmetic ignores it, so a defect with endpoints scores identically to the same defect without them. x2 and y2 must be provided together (dependentRequired, both directions). Only the three linear regions declare them; point-only regions (corner/stain/print_defect) do not."
    },
    "face": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "centering": {
          "type": "object",
          "additionalProperties": false,
          "description": "Measured border centering. 50.0 = perfect. lr_pct = the left border's share of left+right border width; tb_pct = the top border's share of top+bottom. A card described as '60/40 left-right' has lr_pct 60. Defaults to 50/50 if omitted.",
          "properties": {
            "lr_pct": {
              "type": "number",
              "minimum": 0,
              "maximum": 100
            },
            "tb_pct": {
              "type": "number",
              "minimum": 0,
              "maximum": 100
            }
          }
        },
        "defects": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/defect"
          }
        },
        "print": {
          "type": "object",
          "additionalProperties": false,
          "description": "Per-face print-quality attribute ladders (requires a rubric with print_attributes — omit entirely under rubrics that don't define it, or scoring fails loudly). focus, gloss, and border are assessed independently PER FACE — a front can be sharp while the back is slightly out, etc. Penalties are absolute mid-band grade fits and are multiplier-EXEMPT: the front_defect_multiplier applied to corner/edge/surface defects does NOT apply here. Omitting an attribute — or the whole print object — means perfect (no penalty) for that attribute.",
          "properties": {
            "focus": {
              "enum": [
                "sharp",
                "slightly_out",
                "noticeably_out",
                "severely_out"
              ],
              "description": "Print focus/registration sharpness. Grade caps: sharp 10, slightly_out 7, noticeably_out 5, severely_out 2."
            },
            "gloss": {
              "enum": [
                "full",
                "most_retained",
                "some_loss",
                "much_lost",
                "absent"
              ],
              "description": "Surface gloss/sheen retention. Grade caps: full 10, most_retained 7, some_loss 6, much_lost 3, absent 2."
            },
            "border": {
              "enum": [
                "clean",
                "slightly_off_white",
                "yellowed",
                "browned"
              ],
              "description": "Border/paper whiteness. Grade caps: clean 10, slightly_off_white 9, yellowed 3, browned 1.5."
            }
          }
        }
      }
    },
    "defect": {
      "type": "object",
      "$comment": "Defects permit annotation fields; the scorer ignores unknown defect fields. The JSON Schema is stricter than the low-level scorer at surrounding object levels. Every channel requires the same common severity: corner requires corner+severity; edge requires edge+severity; surface requires severity+depth+size+x+y; crease/stain/print_defect require severity+x+y. Only surface/crease/edge validate paired x2/y2 endpoints; endpoints never change a penalty. Legacy severity vocabularies are not accepted.",
      "description": "One defect. One object per distinct flaw; multiple defects may share a corner/edge; penalties sum within the face's region. The named region is canonical for scoring; x,y (normalized 0-1 from the top-left of the face) are REQUIRED for surface, crease, stain, and print_defect defects (location matters for placed flaws) and optional annotation for corner/edge defects. surface/crease/edge defects MAY additionally carry paired line endpoints x2,y2 (see $defs.line_endpoint — presentational/derivation aid, never scored).",
      "required": [
        "region"
      ],
      "properties": {
        "region": {
          "enum": [
            "corner",
            "edge",
            "surface",
            "crease",
            "stain",
            "print_defect"
          ],
          "description": "Every defect requires common severity. Corner/edge also require a locator; surface also requires depth, size, x and y; crease/stain/print_defect require x and y. Input corner maps to scored corners, edge to edges, crease and stain to surface, and print_defect to print. Print exists only with print_attributes."
        },
        "corner": {
          "enum": [
            "tl",
            "tr",
            "bl",
            "br"
          ],
          "description": "Which corner (required when region=corner): tl=top-left, tr=top-right, bl=bottom-left, br=bottom-right."
        },
        "edge": {
          "enum": [
            "top",
            "right",
            "bottom",
            "left"
          ],
          "description": "Which edge (required when region=edge)."
        },
        "severity": {
          "type": "string",
          "description": "Required common severity for every damage channel: de_minimis, minor, moderate, severe. It is a scored input; type, depth and extent remain separate."
        },
        "depth": {
          "enum": [
            "surface",
            "scratch",
            "deep"
          ],
          "description": "Surface defects only. surface: does not break the gloss (scuff, print line). scratch: a visible line you can catch a fingernail on. deep: surface-layer penetration (a gouge), without a stock fold or break. A stock crease, including a light crease with an intact surface, is excluded from deep; use the separate crease vocabulary when a crease is established. No dent mapping is defined. See RUBRIC.md for stated-condition examples and unresolved distinctions."
        },
        "size": {
          "enum": [
            "dot",
            "lt_1cm",
            "lt_5cm",
            "full_card"
          ],
          "description": "Surface defects only. dot: ~2mm or less. lt_1cm: under 1cm. lt_5cm: under 5cm. full_card: spans most of the card."
        },
        "x": {
          "type": "number",
          "minimum": 0,
          "maximum": 1
        },
        "y": {
          "type": "number",
          "minimum": 0,
          "maximum": 1
        },
        "note": {
          "type": "string",
          "maxLength": 200,
          "description": "Free-text annotation; never affects the score."
        }
      },
      "allOf": [
        {
          "if": {
            "properties": {
              "region": {
                "const": "corner"
              }
            },
            "required": [
              "region"
            ]
          },
          "then": {
            "required": [
              "corner",
              "severity"
            ],
            "properties": {
              "severity": {
                "$ref": "#/$defs/severity"
              }
            }
          }
        },
        {
          "if": {
            "properties": {
              "region": {
                "const": "edge"
              }
            },
            "required": [
              "region"
            ]
          },
          "then": {
            "required": [
              "edge",
              "severity"
            ],
            "properties": {
              "severity": {
                "$ref": "#/$defs/severity"
              },
              "x2": {
                "$ref": "#/$defs/line_endpoint"
              },
              "y2": {
                "$ref": "#/$defs/line_endpoint"
              }
            },
            "dependentRequired": {
              "x2": [
                "y2"
              ],
              "y2": [
                "x2"
              ]
            }
          }
        },
        {
          "if": {
            "properties": {
              "region": {
                "const": "surface"
              }
            },
            "required": [
              "region"
            ]
          },
          "then": {
            "required": [
              "depth",
              "size",
              "x",
              "y",
              "severity"
            ],
            "properties": {
              "x2": {
                "$ref": "#/$defs/line_endpoint"
              },
              "y2": {
                "$ref": "#/$defs/line_endpoint"
              },
              "severity": {
                "$ref": "#/$defs/severity"
              }
            },
            "dependentRequired": {
              "x2": [
                "y2"
              ],
              "y2": [
                "x2"
              ]
            }
          }
        },
        {
          "if": {
            "properties": {
              "region": {
                "const": "crease"
              }
            },
            "required": [
              "region"
            ]
          },
          "then": {
            "required": [
              "severity",
              "x",
              "y"
            ],
            "properties": {
              "severity": {
                "$ref": "#/$defs/crease_severity"
              },
              "x2": {
                "$ref": "#/$defs/line_endpoint"
              },
              "y2": {
                "$ref": "#/$defs/line_endpoint"
              }
            },
            "dependentRequired": {
              "x2": [
                "y2"
              ],
              "y2": [
                "x2"
              ]
            }
          }
        },
        {
          "if": {
            "properties": {
              "region": {
                "const": "stain"
              }
            },
            "required": [
              "region"
            ]
          },
          "then": {
            "required": [
              "severity",
              "x",
              "y"
            ],
            "properties": {
              "severity": {
                "$ref": "#/$defs/stain_severity"
              }
            }
          }
        },
        {
          "if": {
            "properties": {
              "region": {
                "const": "print_defect"
              }
            },
            "required": [
              "region"
            ]
          },
          "then": {
            "required": [
              "severity",
              "x",
              "y"
            ],
            "properties": {
              "severity": {
                "$ref": "#/$defs/print_defect_severity"
              }
            }
          }
        }
      ]
    }
  }
}
