net.anisota.graph.wordlist
Schema Diff
+1 -1
Compatibility Analysis
Backward Compatible
No changes detected.
1
1
{
2
2
"id": "net.anisota.graph.wordlist",
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
"words",
12
12
"createdAt"
13
13
],
14
14
"properties": {
15
15
"name": {
16
16
"type": "string",
17
17
"maxLength": 64,
18
18
"description": "Display name for this word list"
19
19
},
20
20
"words": {
21
21
"type": "array",
22
22
"items": {
23
23
"ref": "#word",
24
24
"type": "ref"
25
25
},
26
26
"maxLength": 500,
27
27
"description": "The muted words/phrases in this list"
28
28
},
29
29
"source": {
30
30
"ref": "#source",
31
31
"type": "ref"
32
32
},
33
33
"enabled": {
34
34
"type": "boolean",
35
35
"default": false,
36
36
"description": "Whether this list is currently active. Scheduling and spell effects further gate an enabled list."
37
37
},
38
38
"schedule": {
39
39
"ref": "#schedule",
40
40
"type": "ref",
41
41
"description": "Optional active window. Absent means the list applies at all times while enabled."
42
42
},
43
43
"strength": {
44
44
"type": "integer",
45
45
"maximum": 100,
46
46
"minimum": 0,
47
47
"description": "Mute strength percentage: the share of matching posts this list mutes. Which posts fill that share is decided by match confidence — how many of the list's words hit, whether they landed in the post's own text, a hashtag, or only a quoted post, and how much of the post they account for — so a softened list keeps the squarest matches muted and lets the marginal ones through. Deterministic per post, so a post never flickers. Absent means 100 (mute everything it matches)."
48
48
},
49
49
"createdAt": {
50
50
"type": "string",
51
51
"format": "datetime",
52
52
"description": "When this list was created"
53
53
},
54
54
"treatment": {
55
55
"type": "string",
56
56
"description": "What this list does to a post it mutes, overriding the app-wide muted-words handling: 'hide' removes it from feeds, 'warn' collapses it behind a notice, 'show' leaves it visible and only counts it toward impact. Absent inherits the global setting.",
57
57
"knownValues": [
58
58
"hide",
59
59
"warn",
60
60
"show"
61
61
]
62
62
},
63
63
"updatedAt": {
64
64
"type": "string",
65
65
"format": "datetime",
66
66
"description": "When this list was last modified"
67
67
},
68
68
"description": {
69
69
"type": "string",
70
70
"maxLength": 300,
71
71
"description": "Optional description of what this list covers"
72
72
},
73
73
"targetFeeds": {
74
74
"type": "array",
75
75
"items": {
76
76
"type": "string",
77
77
"maxLength": 512
78
78
},
79
79
"maxLength": 50,
80
80
"description": "Feeds where this list applies: feed generator / list at-uris, or the literal sentinel 'following' for the home timeline. Empty or absent applies everywhere."
81
81
},
82
82
"syncToBluesky": {
83
83
"type": "boolean",
84
84
"default": false,
85
85
"description": "Whether this list's words are also projected into Bluesky's native mutedWordsPref (managed entries, removed when the list is disabled or deleted)."
86
86
}
87
87
}
88
88
},
89
89
"description": "A named, shareable list of muted words/phrases — Anisota's managed layer on top of Bluesky's flat muted-words preference. Each list is a complete, self-contained record so it can be shared by URL and saved (copied) into another user's PDS, mirroring the net.anisota.spell.custom architecture. Muting is applied client-side by the moderation pipeline: multiple enabled lists combine, a list can be scoped to specific feeds, restricted to a time-of-day/day-of-week window, and softened with a strength percentage (mute only that share of matching posts, deterministically per post). A list can optionally be projected into Bluesky's native mutedWordsPref for parity with other clients."
90
90
},
91
91
"word": {
92
92
"type": "object",
93
93
"required": [
94
94
"value"
95
95
],
96
96
"properties": {
97
97
"value": {
98
98
"type": "string",
99
99
"maxLength": 100,
100
100
"description": "The word or phrase to mute"
101
101
},
102
102
"targets": {
103
103
"type": "array",
104
104
"items": {
105
105
"type": "string",
106
106
"knownValues": [
107
107
"content",
108
108
"tag"
109
109
]
110
110
},
111
111
"description": "What to match against: post text ('content') and/or hashtags ('tag'). Absent means both."
112
112
},
113
113
"actorTarget": {
114
114
"type": "string",
115
115
"description": "Whose posts to apply this word to. Absent means 'all'.",
116
116
"knownValues": [
117
117
"all",
118
118
"exclude-following"
119
119
]
120
120
}
121
121
},
122
122
"description": "One muted word or phrase, matching the shape of Bluesky's mutedWord items so a list can be projected into the native preference losslessly."
123
123
},
124
124
"source": {
125
125
"type": "object",
126
126
"properties": {
127
127
"type": {
128
128
"type": "string",
129
129
"knownValues": [
130
130
"original",
131
131
"learned"
132
132
]
133
133
},
134
134
"rootDid": {
135
135
"type": "string",
136
136
"format": "did",
137
137
"description": "DID of the original author at the top of the lineage."
138
138
},
139
139
"rootUri": {
140
140
"type": "string",
141
141
"format": "at-uri",
142
142
"description": "AT URI of the first author's list — the top of the lineage — propagated to every descendant."
143
143
},
144
144
"originalDid": {
145
145
"type": "string",
146
146
"format": "did",
147
147
"description": "DID of the user this list was saved from."
148
148
},
149
149
"originalUri": {
150
150
"type": "string",
151
151
"format": "at-uri",
152
152
"description": "AT URI of the list this copy was saved from (its immediate parent)."
153
153
}
154
154
},
155
155
"description": "Provenance. An 'original' list was created here; a 'learned' list was saved from another user, carrying a backlink to its immediate parent (originalUri/originalDid) and to the top of its lineage (rootUri/rootDid), modelled on net.anisota.spell.custom so save counts can aggregate across re-shares."
156
156
},
157
157
"schedule": {
158
158
"type": "object",
159
159
"properties": {
160
160
"days": {
161
161
"type": "array",
162
162
"items": {
163
163
"type": "integer",
164
164
"maximum": 6,
165
165
"minimum": 0
166
166
},
167
167
"maxLength": 7,
168
168
"description": "Days of week the list is active (0 = Sunday … 6 = Saturday)"
169
169
},
170
170
"endTime": {
171
171
"type": "string",
172
172
"maxLength": 5,
173
173
"description": "Window end as 'HH:MM' local time"
174
174
},
175
175
"startTime": {
176
176
"type": "string",
177
177
"maxLength": 5,
178
178
"description": "Window start as 'HH:MM' local time"
179
179
}
180
180
},
181
-
"description": "A recurring active window. Days and time window combine: the list applies only on the listed days (absent/empty = every day) and only inside the time window (absent = all day). A window whose end is at or before its start wraps past midnight."
181
+
"description": "A recurring active window. Days and time window combine: the list applies only on the listed days (absent/empty = every day) and only inside the time window (absent = all day). A window whose end is before its start wraps past midnight; equal start and end means no time bound (all day on the listed days)."
182
182
}
183
183
},
184
184
"$type": "com.atproto.lexicon.schema",
185
185
"lexicon": 1
186
186
}