{
  "lexicon": 1,
  "id": "org.cannadb.strainEdit",
  "defs": {
    "main": {
      "type": "record",
      "description": "A field-level edit to a strain's living document (collaborative editing). Targets a strain via `subject` (the anchor record of the entity) and carries a sparse patch: scalar field overwrites in `set`, additive ops on open array fields in `add`/`remove`, and field clears in `unset`. The AppView folds accepted edits over the anchor record to materialize the canonical document; this record is one signed contribution, attributed to its publisher DID. See docs/05-collaborative-strains.md.",
      "key": "tid",
      "record": {
        "type": "object",
        "required": ["subject", "createdAt"],
        "properties": {
          "subject": {
            "type": "string",
            "format": "at-uri",
            "description": "AT-URI of the org.cannadb.strain record anchoring the entity this edit targets."
          },
          "basedOn": {
            "type": "string",
            "description": "Materialized revision hash this edit was authored against, for conflict detection. Optional; absent for blind edits."
          },
          "createdAt": {
            "type": "string",
            "format": "datetime",
            "description": "Client-declared timestamp when this edit was created. Also the fold ordering key (ties broken by record URI)."
          },
          "summary": {
            "type": "string",
            "maxGraphemes": 200,
            "maxLength": 2000,
            "description": "Short human edit summary (the commit message). Capped at 200 graphemes (2000 bytes)."
          },
          "set": {
            "type": "ref",
            "ref": "#scalarFields",
            "description": "Scalar and object-valued fields to overwrite (last-writer-wins per field at fold time)."
          },
          "add": {
            "type": "ref",
            "ref": "#arrayFields",
            "description": "Values to add to open array fields (union at fold time)."
          },
          "remove": {
            "type": "ref",
            "ref": "#arrayFields",
            "description": "Values to remove from open array fields (set-difference at fold time)."
          },
          "unset": {
            "type": "array",
            "description": "Field names to clear. Each must be an editable field of org.cannadb.strain.",
            "items": {
              "type": "string",
              "description": "An editable strain field name to clear, e.g., \"growthOdour\"."
            }
          }
        }
      }
    },
    "scalarFields": {
      "type": "object",
      "description": "The strain's scalar and object-valued fields, all optional. Mirrors org.cannadb.strain. Range/yield objects reference the same shapes the strain lexicon defines. Identity fields (name, kind, breeder, holder) are expressible here; whether such an edit is accepted is an AppView fold/governance concern, not a lexicon constraint.",
      "properties": {
        "name": { "type": "string" },
        "kind": { "type": "string", "knownValues": ["strain", "cut"] },
        "shortDescription": { "type": "string" },
        "description": { "type": "string" },
        "sourceUrl": { "type": "string", "format": "uri" },
        "breeder": { "type": "string", "format": "at-uri" },
        "breederName": { "type": "string" },
        "holder": { "type": "string", "format": "at-uri" },
        "holderName": { "type": "string" },
        "originYear": { "type": "integer" },
        "originRegion": { "type": "string" },
        "autoflower": { "type": "boolean" },
        "indicaSativa": { "type": "integer", "minimum": 0, "maximum": 100 },
        "cbdDominant": { "type": "boolean" },
        "generation": { "type": "string" },
        "thcRange": { "type": "ref", "ref": "org.cannadb.strain#cannabinoidRange" },
        "cbdRange": { "type": "ref", "ref": "org.cannadb.strain#cannabinoidRange" },
        "thcCbdRatio": { "type": "string" },
        "cycleTime": { "type": "ref", "ref": "org.cannadb.strain#dayRange" },
        "height": { "type": "ref", "ref": "org.cannadb.strain#heightRange" },
        "yield": { "type": "ref", "ref": "org.cannadb.strain#yieldRange" },
        "growDifficulty": { "type": "string", "knownValues": ["easy", "intermediate", "hard"] },
        "growthOdour": { "type": "string", "knownValues": ["low", "medium", "high"] },
        "cultivationNotes": { "type": "string" },
        "parents": { "type": "array", "items": { "type": "string", "format": "at-uri" } },
        "parentNames": { "type": "array", "items": { "type": "string" } },
        "parentBreederNames": { "type": "array", "items": { "type": "string" } },
        "versionOf": { "type": "array", "items": { "type": "string", "format": "at-uri" } },
        "versionOfNames": { "type": "array", "items": { "type": "string" } }
      }
    },
    "arrayFields": {
      "type": "object",
      "description": "Open array fields that support additive add/remove merge. Lineage arrays (parents/versionOf and their parallel name arrays) are NOT here — they are replaced wholesale via `set` because their parallel-index structure does not merge element-wise.",
      "properties": {
        "alsoKnownAs": { "type": "array", "items": { "type": "string" } },
        "seedAvailability": { "type": "array", "items": { "type": "string", "knownValues": ["regular", "feminized", "autoflower", "clone_only"] } },
        "flavors": { "type": "array", "items": { "type": "string" } },
        "terpenes": { "type": "array", "items": { "type": "string" } },
        "effects": { "type": "array", "items": { "type": "string" } },
        "medicinalEffects": { "type": "array", "items": { "type": "string" } },
        "characteristics": { "type": "array", "items": { "type": "string" } }
      }
    }
  }
}
