fm.freemix.track
Schema Diff
+5 -0
Compatibility Analysis
Backward Compatible
Backward compatible. 2 non-breaking changes.
Non-Breaking Changes (2)
- AddedVertex AddedVertex { vertex_id: "fm.freemix.track:body.artworkSeed" }
- AddedEdge AddedEdge { src: "fm.freemix.track:body", tgt: "fm.freemix.track:body.artworkSeed", kind: "prop", name: Some("artworkSeed") }
Migration Guidance
Added Elements
AddedVertex { vertex_id: "fm.freemix.track:body.artworkSeed" }
Additional Notes
- Non-breaking: AddedEdge { src: "fm.freemix.track:body", tgt: "fm.freemix.track:body.artworkSeed", kind: "prop", name: Some("artworkSeed") }
1
1
{
2
2
"$type": "com.atproto.lexicon.schema",
3
3
"defs": {
4
4
"main": {
5
5
"description": "A music track record on FreeMix. Top-level leaf (FM-549 s38: pulled out from under the release.* prefix; release.track -> track).",
6
6
"key": "tid",
7
7
"record": {
8
8
"properties": {
9
9
"aiDeclaration": {
10
10
"description": "Declaration of AI involvement in creation",
11
11
"properties": {
12
12
"category": {
13
13
"description": "Level of AI involvement",
14
14
"knownValues": [
15
15
"none",
16
16
"assisted",
17
17
"augmented",
18
18
"generated"
19
19
],
20
20
"maxLength": 100,
21
21
"type": "string"
22
22
},
23
23
"description": {
24
24
"description": "Creator's description of how AI was used",
25
25
"maxLength": 1000,
26
26
"type": "string"
27
27
},
28
28
"tools": {
29
29
"description": "AI tools used",
30
30
"items": {
31
31
"maxLength": 100,
32
32
"type": "string"
33
33
},
34
34
"maxLength": 10,
35
35
"type": "array"
36
36
}
37
37
},
38
38
"required": [
39
39
"category"
40
40
],
41
41
"type": "object"
42
42
},
43
43
"artist": {
44
44
"description": "Artist name",
45
45
"maxLength": 200,
46
46
"type": "string"
47
47
},
48
+
"artworkSeed": {
49
+
"description": "FM-729: seed the generative cover placeholder is drawn from. Grammar \"<title>#deck<gen>#regen<n>\"; both counters recompute from this one string, so there are no separate deck/attempt fields. Optional - absent means fall back to the title (the pre-FM-729 implicit seed), which renders the existing cover unchanged. Never an empty string (an empty seed is a fixed point of the generator's LCG and collapses the art). Kept on the record even when coverArtUrl is set, so removing an uploaded cover restores the same generated art. maxLength 384 = title's 300 plus suffix headroom.",
50
+
"maxLength": 384,
51
+
"type": "string"
52
+
},
48
53
"audioDurationMs": {
49
54
"description": "Duration of the track in milliseconds",
50
55
"type": "integer"
51
56
},
52
57
"audioFormat": {
53
58
"description": "Audio file format",
54
59
"knownValues": [
55
60
"wav",
56
61
"flac",
57
62
"mp3",
58
63
"aac",
59
64
"ogg",
60
65
"aiff"
61
66
],
62
67
"maxLength": 100,
63
68
"type": "string"
64
69
},
65
70
"audioHash": {
66
71
"description": "SHA-256 hash of the audio file content",
67
72
"maxLength": 200,
68
73
"type": "string"
69
74
},
70
75
"audioSizeBytes": {
71
76
"description": "Size of the audio file in bytes",
72
77
"type": "integer"
73
78
},
74
79
"audioUrl": {
75
80
"description": "DEPRECATED (FM-508): no longer emitted. Full-quality audio is private (gated download only) and is never surfaced in the portable record. Field kept (optional) to tolerate pre-FM-508 records without a putRecord rewrite.",
76
81
"format": "uri",
77
82
"maxLength": 3000,
78
83
"type": "string"
79
84
},
80
85
"bpmCentis": {
81
86
"description": "Beats per minute in centiBPM (multiply actual BPM by 100, e.g., 174.50 BPM = 17450)",
82
87
"maximum": 99900,
83
88
"minimum": 2000,
84
89
"type": "integer"
85
90
},
86
91
"buyLink": {
87
92
"description": "URL to purchase or stream (Bandcamp, Beatport, Spotify, etc.)",
88
93
"format": "uri",
89
94
"maxLength": 500,
90
95
"type": "string"
91
96
},
92
97
"catalogNumber": {
93
98
"description": "Catalog number (e.g., 'VIZ-042')",
94
99
"maxLength": 100,
95
100
"type": "string"
96
101
},
97
102
"clipUrl": {
98
103
"description": "FM-508: public URL to a short (~30s) truncated audio clip — the record's only public audio artifact. Tracks only; stems and samples never carry a clip. Optional.",
99
104
"format": "uri",
100
105
"maxLength": 3000,
101
106
"type": "string"
102
107
},
103
108
"copyrightComposition": {
104
109
"description": "© line for the composition, e.g. '2026 Joshua Michaels'. FM-550.",
105
110
"maxGraphemes": 128,
106
111
"maxLength": 256,
107
112
"type": "string"
108
113
},
109
114
"copyrightRecording": {
110
115
"description": "℗ line for the sound recording, e.g. '2026 <label>'. FM-550. NOTE: label rides here + the Previously-Released fields, NOT the credits role vocabulary (s41).",
111
116
"maxGraphemes": 128,
112
117
"maxLength": 256,
113
118
"type": "string"
114
119
},
115
120
"coverArtHash": {
116
121
"description": "SHA-256 hash of the cover art",
117
122
"maxLength": 200,
118
123
"type": "string"
119
124
},
120
125
"coverArtUrl": {
121
126
"description": "URL to cover art image",
122
127
"format": "uri",
123
128
"maxLength": 3000,
124
129
"type": "string"
125
130
},
126
131
"createdAt": {
127
132
"description": "Record creation timestamp",
128
133
"format": "datetime",
129
134
"maxLength": 100,
130
135
"type": "string"
131
136
},
132
137
"credits": {
133
138
"description": "Descriptive credit lines (FM-550). Repeatable; multiple entries may share a role. Record-of-fact only — read by NO money/control code (s41). PRO-registration shape, not a split sheet: no percentages, no payout fields.",
134
139
"items": {
135
140
"properties": {
136
141
"did": {
137
142
"description": "ATProto identity of the credited party, when on-network. OPTIONAL and load-bearing — named-but-unlinked credits are the common case.",
138
143
"format": "did",
139
144
"type": "string"
140
145
},
141
146
"ipi": {
142
147
"description": "IPI/CAE number for PRO reconciliation. Optional.",
143
148
"maxLength": 20,
144
149
"type": "string"
145
150
},
146
151
"name": {
147
152
"description": "Credited party's name. Required. Works for off-network parties (sampled composer, session player) with no ATProto identity.",
148
153
"maxGraphemes": 128,
149
154
"maxLength": 256,
150
155
"type": "string"
151
156
},
152
157
"role": {
153
158
"description": "Credit role. OPEN knownValues (not a closed enum) — off-list roles allowed without a lexicon bump; the list is UI-picker guidance.",
154
159
"knownValues": [
155
160
"composer",
156
161
"lyricist",
157
162
"composerLyricist",
158
163
"writer",
159
164
"arranger",
160
165
"adapter",
161
166
"translator",
162
167
"performer",
163
168
"featuredArtist",
164
169
"vocalist",
165
170
"producer",
166
171
"remixer",
167
172
"mixEngineer",
168
173
"masteringEngineer",
169
174
"sampledArtist",
170
175
"originalArtist"
171
176
],
172
177
"maxLength": 64,
173
178
"type": "string"
174
179
}
175
180
},
176
181
"required": [
177
182
"role",
178
183
"name"
179
184
],
180
185
"type": "object"
181
186
},
182
187
"maxLength": 64,
183
188
"type": "array"
184
189
},
185
190
"currency": {
186
191
"description": "ISO-4217 currency code. Phase 1 = USD only. INLINE sellability shape — keep in sync across sellable types.",
187
192
"knownValues": [
188
193
"USD"
189
194
],
190
195
"maxLength": 3,
191
196
"type": "string"
192
197
},
193
198
"derivativeSubType": {
194
199
"description": "The derivative kind for Remix/Edit/Mashup uploads. Absent on Original tracks. Durable provenance — the authoritative signal that a track is a derivative, independent of source count. knownValues (not a closed enum) so future subtypes don't break existing records.",
195
200
"knownValues": [
196
201
"remix",
197
202
"edit",
198
203
"mashup"
199
204
],
200
205
"maxLength": 100,
201
206
"type": "string"
202
207
},
203
208
"description": {
204
209
"description": "Track description",
205
210
"maxLength": 5000,
206
211
"type": "string"
207
212
},
208
213
"genre": {
209
214
"description": "Genre classifications",
210
215
"items": {
211
216
"maxLength": 50,
212
217
"type": "string"
213
218
},
214
219
"maxLength": 5,
215
220
"type": "array"
216
221
},
217
222
"isReleased": {
218
223
"description": "Whether this track was previously released outside FreeMix",
219
224
"type": "boolean"
220
225
},
221
226
"isrc": {
222
227
"description": "International Standard Recording Code (this recording). MIGRATED from the old top-level `isrc` field (FM-549 s41); existing records carrying top-level isrc are relocated here by the T3 data migration.",
223
228
"maxLength": 15,
224
229
"type": "string"
225
230
},
226
231
"iswc": {
227
232
"description": "International Standard Musical Work Code (the composition). FM-550.",
228
233
"maxLength": 15,
229
234
"type": "string"
230
235
},
231
236
"key": {
232
237
"description": "Musical key (e.g., 'Am', 'F#m', 'Bb')",
233
238
"maxLength": 10,
234
239
"type": "string"
235
240
},
236
241
"license": {
237
242
"description": "AT URI to the license grant record",
238
243
"format": "at-uri",
239
244
"maxLength": 3000,
240
245
"type": "string"
241
246
},
242
247
"noAttributableSourcesAttested": {
243
248
"description": "True only when the uploader affirmed via the upload UI that this derivative has no FreeMix-attributable source (own work, licensed, off-platform, or since-deleted). Never set automatically from source count — it is an explicit human attestation, not a computed value.",
244
249
"type": "boolean"
245
250
},
246
251
"priceCents": {
247
252
"description": "On-network price in integer cents (FM-549: price goes on-network; offer is public, sale is private). 0 or absent = free. Hard price floor enforced in app, not schema. INLINE sellability shape — authored identically in fm.freemix.release and fm.freemix.group.stemsGroup; keep in sync (s41).",
248
253
"minimum": 0,
249
254
"type": "integer"
250
255
},
251
256
"releaseDate": {
252
257
"description": "Original release date (ISO 8601)",
253
258
"format": "datetime",
254
259
"type": "string"
255
260
},
256
261
"releaseLabel": {
257
262
"description": "Label name (e.g., 'Vizual Records', 'self-released')",
258
263
"maxLength": 255,
259
264
"type": "string"
260
265
},
261
266
"seller": {
262
267
"description": "parties.seller (s39): the single account DID that owns and sells this item (owner = seller = uploader; may be an org account). Charge/entitlement read THIS field. One-field indirection from record author. INLINE — keep in sync.",
263
268
"format": "did",
264
269
"type": "string"
265
270
},
266
271
"stemAccess": {
267
272
"description": "Who can access stems. Defaults to 'open'. Phase 1 only supports 'open' and 'community'.",
268
273
"knownValues": [
269
274
"open",
270
275
"community",
271
276
"request",
272
277
"pro"
273
278
],
274
279
"maxLength": 100,
275
280
"type": "string"
276
281
},
277
282
"tags": {
278
283
"description": "Freeform tags",
279
284
"items": {
280
285
"maxLength": 50,
281
286
"type": "string"
282
287
},
283
288
"maxLength": 10,
284
289
"type": "array"
285
290
},
286
291
"title": {
287
292
"description": "Track title",
288
293
"maxLength": 300,
289
294
"type": "string"
290
295
}
291
296
},
292
297
"required": [
293
298
"title",
294
299
"artist",
295
300
"audioHash",
296
301
"audioFormat",
297
302
"audioSizeBytes",
298
303
"license",
299
304
"createdAt"
300
305
],
301
306
"type": "object"
302
307
},
303
308
"type": "record"
304
309
}
305
310
},
306
311
"id": "fm.freemix.track",
307
312
"lexicon": 1
308
313
}