org.cannadb.strain

cannadb.org

Schema Diff

+2 -2

From

CID
bafyreieu2pycseu...
Indexed At
2026-06-18 16:25 UTC
View this version

To

CID
bafyreidajssfwbc...
Indexed At
2026-06-20 00:44 UTC
View this version

Compatibility Analysis

Backward Compatible

No changes detected.

1 1
{
2 2
  "id": "org.cannadb.strain",
3 3
  "defs": {
4 4
    "main": {
5 5
      "key": "tid",
6 6
      "type": "record",
7 7
      "record": {
8 8
        "type": "object",
9 9
        "required": [
10 10
          "name",
11 11
          "kind",
12 12
          "createdAt"
13 13
        ],
14 14
        "properties": {
15 15
          "kind": {
16 16
            "type": "string",
17 17
            "description": "Level of specificity. \"strain\" = broad genetic identity; \"cut\" = a specific phenotype, clone, or keeper pheno of a strain. Open vocabulary — clients should accept unknown values gracefully and fall back to generic display.",
18 18
            "knownValues": [
19 19
              "strain",
20 20
              "cut"
21 21
            ]
22 22
          },
23 23
          "name": {
24 24
            "type": "string",
25 25
            "description": "Primary common name of the strain or cut, e.g., \"Wedding Cake\" or \"Forum cut of GSC\"."
26 26
          },
27 27
          "yield": {
28 28
            "ref": "#yieldRange",
29 29
            "type": "ref",
30 30
            "description": "Claimed yield as a min/max integer range plus a `unit` enum so the integer is unambiguous. Single-value quotes set min == max. The unit is required to interpret the integer correctly — a lexicon convention because breeders quote yield in mutually incompatible units (per-plant vs per-m², grams vs ounces) and an unlabeled integer is unsafe."
31 31
          },
32 32
          "height": {
33 33
            "ref": "#heightRange",
34 34
            "type": "ref",
35 35
            "description": "Plant height at maturity in centimeters, expressed as a min/max range. Conventional basis is indoor mature (the breeder's typical quote). Outdoor mature heights run substantially larger; outdoor-quoted values should be flagged in `cultivationNotes` rather than smashed into this field."
36 36
          },
37 37
          "holder": {
38 38
            "type": "string",
39 39
            "format": "at-uri",
40 40
            "description": "For cut records: AT-URI reference (typically a DID) to the holder of this specific cut. `holderName` is the display fallback."
41 41
          },
42 42
          "breeder": {
43 43
            "type": "string",
44 44
            "format": "at-uri",
45 45
            "description": "AT-URI reference to an `org.cannadb.breeder` record. Canonical when present and resolvable; `breederName` is the display fallback. (The lexicon spec does not enforce collection constraints on at-uri; consumers should validate the ref resolves to an `org.cannadb.breeder` record.)"
46 46
          },
47 47
          "effects": {
48 48
            "type": "array",
49 49
            "items": {
50 50
              "type": "string",
51 51
              "description": "A single recreational effect descriptor."
52 52
            },
53 53
            "description": "Claimed recreational effect descriptors. Open vocabulary — see `flavors` for rationale. Distinct from `medicinalEffects`, which is a parallel vocabulary for therapeutic claims."
54 54
          },
55 55
          "flavors": {
56 56
            "type": "array",
57 57
            "items": {
58 58
              "type": "string",
59 59
              "description": "A single flavor descriptor."
60 60
            },
61 61
            "description": "Claimed flavor profile descriptors. Open vocabulary — the lexicon does not enforce a closed set; the AppView normalizes near-duplicates at index time and may ship a curated suggestion list for autocomplete."
62 62
          },
63 63
          "parents": {
64 64
            "type": "array",
65 65
            "items": {
66 66
              "type": "string",
67 67
              "format": "at-uri",
68 68
              "description": "AT-URI reference to a parent `org.cannadb.strain` record."
69 69
            },
70 70
            "description": "Genetic ancestry — AT-URI references to parent `org.cannadb.strain` records (typically 1–2 entries). `parentNames` provides display fallbacks; `parentBreederNames` provides per-parent breeder attribution as a parallel array. (The lexicon spec does not enforce collection constraints on at-uri; consumers should validate refs resolve to `org.cannadb.strain` records.)"
71 71
          },
72 72
          "cbdRange": {
73 73
            "ref": "#cannabinoidRange",
74 74
            "type": "ref",
75 75
            "description": "Claimed CBD percentage range. Values are integers in hundredths of a percent (e.g., 75 = 0.75%). Optional; either bound may be omitted if only one is known."
76 76
          },
77 77
          "terpenes": {
78 78
            "type": "array",
79 79
            "items": {
80 80
              "type": "string",
81 81
              "description": "A single terpene name."
82 82
            },
83 83
            "description": "Claimed dominant terpenes. Open vocabulary — see `flavors` for rationale."
84 84
          },
85 85
          "thcRange": {
86 86
            "ref": "#cannabinoidRange",
87 87
            "type": "ref",
88 88
            "description": "Claimed THC percentage range. Values are integers in hundredths of a percent (e.g., 2450 = 24.50%). Optional; either bound may be omitted if only one is known."
89 89
          },
90 90
          "createdAt": {
91 91
            "type": "string",
92 92
            "format": "datetime",
93 93
            "description": "Client-declared timestamp when this record was originally created."
94 94
          },
95 95
          "cycleTime": {
96 96
            "ref": "#dayRange",
97 97
            "type": "ref",
98 98
            "description": "Cycle time in days, expressed as a min/max range. Basis derives from `autoflower`: full-run (germination → harvest) for autoflowers, flower-only (start of 12/12 → harvest) for photoperiods. Single-value quotes set min == max. The basis is not stored separately because it derives from `autoflower`; documenting the convention here prevents downstream tools from misinterpreting the integer."
99 99
          },
100 100
          "sourceUrl": {
101 101
            "type": "string",
102 102
            "format": "uri",
103 103
            "description": "Optional URL pointing at the canonical breeder/origin write-up for this strain — typically the breeder's product page or a strain-specific writeup. Distinct from the breeder record's `website` (the breeder's home page); this is the strain-specific page. No link-rot guarantee; informational only."
104 104
          },
105 105
          "versionOf": {
106 106
            "type": "array",
107 107
            "items": {
108 108
              "type": "string",
109 109
              "format": "at-uri",
110 110
              "description": "AT-URI reference to an `org.cannadb.strain` record this record claims a derivative or equivalence relationship with."
111 111
            },
112 112
            "description": "Derivative or claimed relationships — AT-URI references to `org.cannadb.strain` records this record is sold as, claims to be, or is a take on. Distinct from `parents` (genetic ancestry): a pure relabel has `versionOf` but no `parents`; a derivative breeding take may have both. Includes the autoflower-take-on-a-photo pattern (an autoflower variant of \"the same strain\" is a `versionOf` claim even though its `parents` may differ because a ruderalis line was crossed in)."
113 113
          },
114 114
          "autoflower": {
115 115
            "type": "boolean",
116 116
            "description": "Whether this strain or cut is autoflowering (i.e., has ruderalis influence). Orthogonal to indica/sativa lean. Also conditions the basis of `cycleTime`: full-run (germination → harvest) for autoflowers, flower-only for photoperiods."
117 117
          },
118 118
          "generation": {
119 119
            "type": "string",
120 120
            "description": "Free-form generation marker for the strain's own generation (e.g., \"F7\", \"BX3\", \"S1\", \"Selection\"). Free-form because the vocabulary is open and breeders write whatever shorthand fits. Parent strains' generations stay inline in `parentNames` strings."
121 121
          },
122 122
          "holderName": {
123 123
            "type": "string",
124 124
            "description": "Display fallback for the cut holder."
125 125
          },
126 126
          "originYear": {
127 127
            "type": "integer",
128 128
            "description": "Year the strain or cut was first introduced."
129 129
          },
130 130
          "alsoKnownAs": {
131 131
            "type": "array",
132 132
            "items": {
133 133
              "type": "string",
134 134
              "description": "An alternate display name for this strain or cut."
135 135
            },
136 136
            "description": "Alternate names this strain or cut is known by, e.g., [\"Triangle Mints #23\"]."
137 137
          },
138 138
          "breederName": {
139 139
            "type": "string",
140 140
            "description": "Display fallback for the breeder name. Used when no `breeder` ref is available, when the ref does not resolve, or for breeders without atproto presence."
141 141
          },
142 142
          "cbdDominant": {
143 143
            "type": "boolean",
144 144
            "description": "Whether this is a CBD-dominant strain. Orthogonal to the indica/sativa axis (a strain can be both indica-leaning and CBD-dominant). Distinct from `cbdRange` (which is the quantitative CBD percentage); `cbdDominant` is the category signal — cannabis culture treats CBD-dominant strains as a distinct shopping category, not just a high-CBD variant."
145 145
          },
146 146
          "description": {
147 147
            "type": "string",
148 148
            "maxLength": 100000,
149 149
            "description": "Markdown-formatted identity narrative — what this strain is, where it came from, the breeder's intent, the character. Distinct from `cultivationNotes`, which is for cultivators. Capped at 10000 graphemes (100000 bytes).",
150 150
            "maxGraphemes": 10000
151 151
          },
152 152
          "growthOdour": {
153 153
            "type": "string",
154 154
            "description": "Claimed growth odour intensity. Practical for stealth growers. `knownValues` for forward-compat.",
155 155
            "knownValues": [
156 156
              "low",
157 157
              "medium",
158 158
              "high"
159 159
            ]
160 160
          },
161 161
          "parentNames": {
162 162
            "type": "array",
163 163
            "items": {
164 164
              "type": "string",
165 165
              "description": "Display name of a parent strain."
166 166
            },
167 167
            "description": "Display fallbacks for parent strains. Used when refs are absent or unresolved. Phenotype designations, generation markers, and uncertainty markers may be embedded inline in the string (e.g., \"Triangle Mints #23 [pheno: keeper] (F3)\") — clients render them as written."
168 168
          },
169 169
          "thcCbdRatio": {
170 170
            "type": "string",
171 171
            "description": "Claimed THC:CBD ratio expressed as a string, e.g., \"1:1\", \"20:1\"."
172 172
          },
173 173
          "indicaSativa": {
174 174
            "type": "integer",
175 175
            "maximum": 100,
176 176
            "minimum": 0,
177 177
            "description": "Indica/sativa lean on a 0–100 scale, where 0 is pure indica and 100 is pure sativa. Pure landraces sit at the extremes; modern hybrids fall between."
178 178
          },
179 179
          "originRegion": {
180 180
            "type": "string",
181 181
            "description": "Region of geographic origin, e.g., \"Hindu Kush\", \"California\"."
182 182
          },
183 183
          "primaryImage": {
184 184
            "type": "blob",
185 185
            "accept": [
186 186
              "image/png",
187 187
              "image/jpeg",
188 188
              "image/webp"
189 189
            ],
190 -
            "maxSize": 1000000,
191 -
            "description": "One representative image of the strain or cut. Accepts common web image formats; capped at 1 MB to keep PDS storage burden modest. Higher-resolution photography belongs in review or grow records."
190 +
            "maxSize": 2000000,
191 +
            "description": "One representative image of the strain or cut. Accepts common web image formats; capped at 2 MB to keep PDS storage burden modest. Higher-resolution photography belongs in review or grow records."
192 192
          },
193 193
          "growDifficulty": {
194 194
            "type": "string",
195 195
            "description": "Claimed grow difficulty. `knownValues` for forward-compat — clients should accept unknown values and fall back to generic display.",
196 196
            "knownValues": [
197 197
              "easy",
198 198
              "intermediate",
199 199
              "hard"
200 200
            ]
201 201
          },
202 202
          "versionOfNames": {
203 203
            "type": "array",
204 204
            "items": {
205 205
              "type": "string",
206 206
              "description": "Display name of a strain this record is a version of."
207 207
            },
208 208
            "description": "Display fallbacks for `versionOf` references."
209 209
          },
210 210
          "characteristics": {
211 211
            "type": "array",
212 212
            "items": {
213 213
              "type": "string",
214 214
              "description": "A single plant characteristic descriptor."
215 215
            },
216 216
            "description": "Plant trait descriptors orthogonal to consumption experience. Open vocabulary; parallel to `effects`/`medicinalEffects`/`flavors` but for properties of the plant rather than the experience of consuming it. Examples: \"mold resistant\", \"frost tolerant\", \"high flower-to-leaf ratio\", \"drought tolerant\". The AppView normalizes near-duplicates at index time."
217 217
          },
218 218
          "cultivationNotes": {
219 219
            "type": "string",
220 220
            "maxLength": 100000,
221 221
            "description": "Markdown-formatted cultivation guidance from the publisher — overflow for context that doesn't fit the structured `cycleTime`, `height`, `yield`, `growDifficulty`, `growthOdour` fields. Things like indoor/outdoor recommendations, environmental sensitivities, training notes, and run-specific quirks belong here. Capped at 10000 graphemes (100000 bytes).",
222 222
            "maxGraphemes": 10000
223 223
          },
224 224
          "medicinalEffects": {
225 225
            "type": "array",
226 226
            "items": {
227 227
              "type": "string",
228 228
              "description": "A single medicinal effect descriptor."
229 229
            },
230 230
            "description": "Claimed medical/therapeutic effect descriptors. Open vocabulary; parallel to `effects` but for medicinal/therapeutic claims distinct from recreational. Examples: \"insomnia relief\", \"appetite stimulation\", \"anxiety relief\". The AppView normalizes near-duplicates at index time."
231 231
          },
232 232
          "seedAvailability": {
233 233
            "type": "array",
234 234
            "items": {
235 235
              "type": "string",
236 236
              "description": "A single seed variant identifier.",
237 237
              "knownValues": [
238 238
                "regular",
239 239
                "feminized",
240 240
                "autoflower",
241 241
                "clone_only"
242 242
              ]
243 243
            },
244 244
            "description": "What variants exist for this strain name. Multi-valued because a strain often ships in multiple variants. Open vocabulary via `knownValues` so additive expansions (e.g., a future \"feminized_autoflower\" composite value) don't require a lexicon revision."
245 245
          },
246 246
          "shortDescription": {
247 247
            "type": "string",
248 248
            "maxLength": 2000,
249 249
            "description": "Single-line plain-text summary used in card meta lines, search-result excerpts, and social-share previews. Markdown is disallowed; this is a one-line summary distinct from the full markdown `description`. Capped at 250 graphemes (2000 bytes) — enforced by the lexicon to keep card meta lines and share previews short.",
250 250
            "maxGraphemes": 250
251 251
          },
252 252
          "parentBreederNames": {
253 253
            "type": "array",
254 254
            "items": {
255 255
              "type": "string",
256 256
              "description": "Display name of the breeder of the parent at the same index in `parentNames`. Empty string when unknown."
257 257
            },
258 258
            "description": "Optional parallel array to `parentNames` capturing per-parent breeder attribution (e.g., [\"Karma Genetics\", \"\"] when the first parent's breeder is known and the second's is not). Index-aligned with `parentNames`: position N in this array attributes the breeder of the parent at position N in `parentNames`. Empty strings or missing trailing entries indicate unknown attribution. Forward-compat note: phenotype designations, generation markers, and uncertainty markers stay inline in the parent name string until evidence shows they need their own structure."
259 259
          }
260 260
        }
261 261
      },
262 262
      "description": "Cannabis genetic identity. The same record type covers two levels of specificity, distinguished by the `kind` field: \"strain\" denotes a broad genetic identity (e.g., \"Wedding Cake\"); \"cut\" denotes a specific phenotype, clone, or keeper pheno (e.g., \"Forum cut of GSC\"). Captures intrinsic identity, structured cultivation profile, and the publisher's contextualized field assertions; subjective experience and measured outcomes live in separate record types (`org.cannadb.review`, future `org.cannadb.grow`) that reference this one. Publishing this record IS the claim — every field below is implicitly contextualized by the publisher's identity, computed by consumers from the publisher DID at display time."
263 263
    },
264 264
    "dayRange": {
265 265
      "type": "object",
266 266
      "properties": {
267 267
        "max": {
268 268
          "type": "integer",
269 269
          "maximum": 365,
270 270
          "minimum": 0,
271 271
          "description": "Upper bound in days."
272 272
        },
273 273
        "min": {
274 274
          "type": "integer",
275 275
          "maximum": 365,
276 276
          "minimum": 0,
277 277
          "description": "Lower bound in days."
278 278
        }
279 279
      },
280 280
      "description": "A min/max integer range expressed in whole days. Both bounds independently optional; single-value quotes set min == max. Atproto's data model has no float type, so all numeric fields use integers; days are a natural integer unit and need no further scaling."
281 281
    },
282 282
    "yieldRange": {
283 283
      "type": "object",
284 284
      "properties": {
285 285
        "max": {
286 286
          "type": "integer",
287 287
          "minimum": 0,
288 288
          "description": "Upper bound, in the unit specified by `unit`."
289 289
        },
290 290
        "min": {
291 291
          "type": "integer",
292 292
          "minimum": 0,
293 293
          "description": "Lower bound, in the unit specified by `unit`."
294 294
        },
295 295
        "unit": {
296 296
          "type": "string",
297 297
          "description": "Unit of `min`/`max`. `g_per_plant` = grams per plant; `g_per_m2` = grams per square meter; `oz_per_plant` = ounces per plant; `oz_per_m2` = ounces per square meter. `knownValues` rather than a closed enum so additive unit expansions don't require a lexicon revision.",
298 298
          "knownValues": [
299 299
            "g_per_plant",
300 300
            "g_per_m2",
301 301
            "oz_per_plant",
302 302
            "oz_per_m2"
303 303
          ]
304 304
        }
305 305
      },
306 306
      "description": "A min/max integer range plus a `unit` enum so the integer is unambiguous. Single-value quotes set min == max. The unit is what makes the integer interpretable — breeders quote yield in mutually incompatible units (per-plant vs per-m², grams vs ounces), so consumers must read `unit` before interpreting `min`/`max`."
307 307
    },
308 308
    "heightRange": {
309 309
      "type": "object",
310 310
      "properties": {
311 311
        "max": {
312 312
          "type": "integer",
313 313
          "maximum": 2000,
314 314
          "minimum": 0,
315 315
          "description": "Upper bound in centimeters."
316 316
        },
317 317
        "min": {
318 318
          "type": "integer",
319 319
          "maximum": 2000,
320 320
          "minimum": 0,
321 321
          "description": "Lower bound in centimeters."
322 322
        }
323 323
      },
324 324
      "description": "A min/max integer range expressed in whole centimeters. Both bounds independently optional; single-value quotes set min == max. Centimeters are a natural integer unit and need no further scaling."
325 325
    },
326 326
    "cannabinoidRange": {
327 327
      "type": "object",
328 328
      "properties": {
329 329
        "max": {
330 330
          "type": "integer",
331 331
          "maximum": 10000,
332 332
          "minimum": 0,
333 333
          "description": "Upper bound, in hundredths of a percent (e.g., 2700 = 27.00%)."
334 334
        },
335 335
        "min": {
336 336
          "type": "integer",
337 337
          "maximum": 10000,
338 338
          "minimum": 0,
339 339
          "description": "Lower bound, in hundredths of a percent (e.g., 2000 = 20.00%)."
340 340
        }
341 341
      },
342 342
      "description": "A min/max integer range for a cannabinoid percentage, expressed in hundredths of a percent (e.g., 2450 = 24.50%). Both bounds are independently optional; either may be omitted when only one is known."
343 343
    }
344 344
  },
345 345
  "$type": "com.atproto.lexicon.schema",
346 346
  "lexicon": 1
347 347
}

Compare Other Versions

Lexicon Garden

@