at.eptss.candidateLedger
Schema Diff
+20 -23
Compatibility Analysis
Breaking Changes Detected
18 breaking changes, 9 non-breaking changes.
Breaking Changes (18)
- RequiredEdgeAdded RequiredEdgeAdded { vertex_id: "at.eptss.candidateLedger:body", src: "at.eptss.candidateLedger:body", tgt: "at.eptss.candidateLedger:body.playlist", kind: "prop", name: Some("playlist") }
- RequiredEdgeAdded RequiredEdgeAdded { vertex_id: "at.eptss.candidateLedger:body", src: "at.eptss.candidateLedger:body", tgt: "at.eptss.candidateLedger:body.nominations", kind: "prop", name: Some("nominations") }
- RequiredEdgeAdded RequiredEdgeAdded { vertex_id: "at.eptss.candidateLedger#nomination", src: "at.eptss.candidateLedger#nomination", tgt: "at.eptss.candidateLedger#nomination.by", kind: "prop", name: Some("by") }
- RequiredEdgeAdded RequiredEdgeAdded { vertex_id: "at.eptss.candidateLedger#nomination", src: "at.eptss.candidateLedger#nomination", tgt: "at.eptss.candidateLedger#nomination.track", kind: "prop", name: Some("track") }
- RequiredEdgeRemoved RequiredEdgeRemoved { vertex_id: "at.eptss.candidateLedger#candidate", src: "at.eptss.candidateLedger#candidate", tgt: "at.eptss.candidateLedger#candidate.title", kind: "prop", name: Some("title") }
- RequiredEdgeRemoved RequiredEdgeRemoved { vertex_id: "at.eptss.candidateLedger#candidate", src: "at.eptss.candidateLedger#candidate", tgt: "at.eptss.candidateLedger#candidate.artist", kind: "prop", name: Some("artist") }
- RequiredEdgeRemoved RequiredEdgeRemoved { vertex_id: "at.eptss.candidateLedger:body", src: "at.eptss.candidateLedger:body", tgt: "at.eptss.candidateLedger:body.candidates", kind: "prop", name: Some("candidates") }
- RemovedVertex RemovedVertex { vertex_id: "at.eptss.candidateLedger#candidate" }
- RemovedVertex RemovedVertex { vertex_id: "at.eptss.candidateLedger#candidate.artist" }
- RemovedVertex RemovedVertex { vertex_id: "at.eptss.candidateLedger#candidate.listenLink" }
- RemovedVertex RemovedVertex { vertex_id: "at.eptss.candidateLedger#candidate.nominatedBy" }
- RemovedVertex RemovedVertex { vertex_id: "at.eptss.candidateLedger#candidate.title" }
- RemovedVertex RemovedVertex { vertex_id: "at.eptss.candidateLedger:body.candidates" }
- RemovedVertex RemovedVertex { vertex_id: "at.eptss.candidateLedger:body.candidates:items" }
- RemovedEdge RemovedEdge { src: "at.eptss.candidateLedger#candidate", tgt: "at.eptss.candidateLedger#candidate.listenLink", kind: "prop", name: Some("listenLink") }
- RemovedEdge RemovedEdge { src: "at.eptss.candidateLedger#candidate", tgt: "at.eptss.candidateLedger#candidate.nominatedBy", kind: "prop", name: Some("nominatedBy") }
- RemovedEdge RemovedEdge { src: "at.eptss.candidateLedger:body.candidates", tgt: "at.eptss.candidateLedger:body.candidates:items", kind: "items", name: None }
- RemovedEdge RemovedEdge { src: "at.eptss.candidateLedger:body.candidates:items", tgt: "at.eptss.candidateLedger#candidate", kind: "ref", name: None }
Non-Breaking Changes (9)
- AddedVertex AddedVertex { vertex_id: "at.eptss.candidateLedger#nomination" }
- AddedVertex AddedVertex { vertex_id: "at.eptss.candidateLedger#nomination.by" }
- AddedVertex AddedVertex { vertex_id: "at.eptss.candidateLedger#nomination.track" }
- AddedVertex AddedVertex { vertex_id: "at.eptss.candidateLedger:body.nominations" }
- AddedVertex AddedVertex { vertex_id: "at.eptss.candidateLedger:body.nominations:items" }
- AddedVertex AddedVertex { vertex_id: "at.eptss.candidateLedger:body.playlist" }
- AddedEdge AddedEdge { src: "at.eptss.candidateLedger:body.nominations", tgt: "at.eptss.candidateLedger:body.nominations:items", kind: "items", name: None }
- AddedEdge AddedEdge { src: "at.eptss.candidateLedger:body.nominations:items", tgt: "at.eptss.candidateLedger#nomination", kind: "ref", name: None }
- AddedEdge AddedEdge { src: "at.eptss.candidateLedger:body.playlist", tgt: "com.atproto.repo.strongRef", kind: "ref", name: None }
Migration Guidance
Removed Elements
RemovedVertex { vertex_id: "at.eptss.candidateLedger#candidate" }RemovedVertex { vertex_id: "at.eptss.candidateLedger#candidate.artist" }RemovedVertex { vertex_id: "at.eptss.candidateLedger#candidate.listenLink" }RemovedVertex { vertex_id: "at.eptss.candidateLedger#candidate.nominatedBy" }RemovedVertex { vertex_id: "at.eptss.candidateLedger#candidate.title" }RemovedVertex { vertex_id: "at.eptss.candidateLedger:body.candidates" }RemovedVertex { vertex_id: "at.eptss.candidateLedger:body.candidates:items" }
Added Elements
AddedVertex { vertex_id: "at.eptss.candidateLedger#nomination" }AddedVertex { vertex_id: "at.eptss.candidateLedger#nomination.by" }AddedVertex { vertex_id: "at.eptss.candidateLedger#nomination.track" }AddedVertex { vertex_id: "at.eptss.candidateLedger:body.nominations" }AddedVertex { vertex_id: "at.eptss.candidateLedger:body.nominations:items" }AddedVertex { vertex_id: "at.eptss.candidateLedger:body.playlist" }
Additional Notes
- Breaking: RequiredEdgeAdded { vertex_id: "at.eptss.candidateLedger:body", src: "at.eptss.candidateLedger:body", tgt: "at.eptss.candidateLedger:body.playlist", kind: "prop", name: Some("playlist") }
- Breaking: RequiredEdgeAdded { vertex_id: "at.eptss.candidateLedger:body", src: "at.eptss.candidateLedger:body", tgt: "at.eptss.candidateLedger:body.nominations", kind: "prop", name: Some("nominations") }
- Breaking: RequiredEdgeAdded { vertex_id: "at.eptss.candidateLedger#nomination", src: "at.eptss.candidateLedger#nomination", tgt: "at.eptss.candidateLedger#nomination.by", kind: "prop", name: Some("by") }
- Breaking: RequiredEdgeAdded { vertex_id: "at.eptss.candidateLedger#nomination", src: "at.eptss.candidateLedger#nomination", tgt: "at.eptss.candidateLedger#nomination.track", kind: "prop", name: Some("track") }
- Breaking: RequiredEdgeRemoved { vertex_id: "at.eptss.candidateLedger:body", src: "at.eptss.candidateLedger:body", tgt: "at.eptss.candidateLedger:body.candidates", kind: "prop", name: Some("candidates") }
- Breaking: RequiredEdgeRemoved { vertex_id: "at.eptss.candidateLedger#candidate", src: "at.eptss.candidateLedger#candidate", tgt: "at.eptss.candidateLedger#candidate.title", kind: "prop", name: Some("title") }
- Breaking: RequiredEdgeRemoved { vertex_id: "at.eptss.candidateLedger#candidate", src: "at.eptss.candidateLedger#candidate", tgt: "at.eptss.candidateLedger#candidate.artist", kind: "prop", name: Some("artist") }
- Breaking: RemovedEdge { src: "at.eptss.candidateLedger#candidate", tgt: "at.eptss.candidateLedger#candidate.listenLink", kind: "prop", name: Some("listenLink") }
- Breaking: RemovedEdge { src: "at.eptss.candidateLedger#candidate", tgt: "at.eptss.candidateLedger#candidate.nominatedBy", kind: "prop", name: Some("nominatedBy") }
- Breaking: RemovedEdge { src: "at.eptss.candidateLedger:body.candidates", tgt: "at.eptss.candidateLedger:body.candidates:items", kind: "items", name: None }
- Breaking: RemovedEdge { src: "at.eptss.candidateLedger:body.candidates:items", tgt: "at.eptss.candidateLedger#candidate", kind: "ref", name: None }
- Non-breaking: AddedEdge { src: "at.eptss.candidateLedger:body.nominations", tgt: "at.eptss.candidateLedger:body.nominations:items", kind: "items", name: None }
- Non-breaking: AddedEdge { src: "at.eptss.candidateLedger:body.nominations:items", tgt: "at.eptss.candidateLedger#nomination", kind: "ref", name: None }
- Non-breaking: AddedEdge { src: "at.eptss.candidateLedger:body.playlist", tgt: "com.atproto.repo.strongRef", kind: "ref", name: None }
1
1
{
2
2
"id": "at.eptss.candidateLedger",
3
3
"defs": {
4
4
"main": {
5
5
"key": "any",
6
6
"type": "record",
7
7
"record": {
8
8
"type": "object",
9
9
"required": [
10
10
"round",
11
-
"candidates",
11
+
"playlist",
12
+
"nominations",
12
13
"publishedAt"
13
14
],
14
15
"properties": {
15
16
"round": {
16
17
"ref": "com.atproto.repo.strongRef",
17
18
"type": "ref",
18
19
"description": "The at.atjam.round this ledger belongs to."
19
20
},
20
-
"candidates": {
21
+
"playlist": {
22
+
"ref": "com.atproto.repo.strongRef",
23
+
"type": "ref",
24
+
"description": "The at.atjam.playlist holding the candidates, in ballot order, CID-pinned."
25
+
},
26
+
"nominations": {
21
27
"type": "array",
22
28
"items": {
23
-
"ref": "#candidate",
29
+
"ref": "#nomination",
24
30
"type": "ref"
25
31
},
26
32
"maxLength": 256,
27
-
"minLength": 1
33
+
"description": "Who put what in the hat. Empty when every candidate was organizer-carried. Tracks absent here are carried candidates, unattributed by design."
28
34
},
29
35
"publishedAt": {
30
36
"type": "string",
31
37
"format": "datetime"
32
38
}
33
39
}
34
40
},
35
-
"description": "The round's ballot sheet: every nominated song, revealed as one atomic record when signups close. Published by the round organizer. nominatedBy links a candidate to its nominator; entries carried over by an organizer omit it. The organizer is responsible for honoring un-naming requests by editing this record in place."
41
+
"description": "The round's ballot sheet, revealed as one atomic record when signups close. Published by the round organizer. The candidate list itself lives in an at.atjam.playlist of at.eptss.track records — this record pins that playlist by CID and adds only what a playlist must never carry: round attribution and who nominated what. Ballots strong-ref this ledger, so the pin chain runs ballot → ledger → playlist → tracks, and a post-hoc edit anywhere is detectable. Attribution keys on the track's AT-URI, never on its position — a positional array desyncs silently on one reorder. The organizer honors un-naming requests by editing nominations in place."
36
42
},
37
-
"candidate": {
43
+
"nomination": {
38
44
"type": "object",
39
45
"required": [
40
-
"title",
41
-
"artist"
46
+
"track",
47
+
"by"
42
48
],
43
49
"properties": {
44
-
"title": {
45
-
"type": "string",
46
-
"maxLength": 5120,
47
-
"maxGraphemes": 512
48
-
},
49
-
"artist": {
50
-
"type": "string",
51
-
"maxLength": 5120,
52
-
"maxGraphemes": 512
53
-
},
54
-
"listenLink": {
50
+
"by": {
55
51
"type": "string",
56
-
"format": "uri"
52
+
"format": "did",
53
+
"description": "DID of the member who nominated it."
57
54
},
58
-
"nominatedBy": {
55
+
"track": {
59
56
"type": "string",
60
-
"format": "did",
61
-
"description": "DID of the member who nominated this song. Absent for organizer-carried candidates."
57
+
"format": "at-uri",
58
+
"description": "The at.eptss.track this attribution is about. A URI and not an index: identity, not position."
62
59
}
63
60
}
64
61
}
65
62
},
66
63
"$type": "com.atproto.lexicon.schema",
67
64
"lexicon": 1
68
65
}