net.anisota.graph.wordlist

anisota.net

Schema Diff

+11 -2

From

CID
bafyreidfu5yh2qt...
Indexed At
2026-07-26 20:11 UTC
View this version

To

CID
bafyreiaq6akunvv...
Indexed At
2026-08-21 20:18 UTC
View this version

Compatibility Analysis

Backward Compatible

Backward compatible. 2 non-breaking changes.

Non-Breaking Changes (2)
  • AddedVertex AddedVertex { vertex_id: "net.anisota.graph.wordlist:body.treatment" }
  • AddedEdge AddedEdge { src: "net.anisota.graph.wordlist:body", tgt: "net.anisota.graph.wordlist:body.treatment", kind: "prop", name: Some("treatment") }

Migration Guidance

Added Elements

  • AddedVertex { vertex_id: "net.anisota.graph.wordlist:body.treatment" }

Additional Notes

  • Non-breaking: AddedEdge { src: "net.anisota.graph.wordlist:body", tgt: "net.anisota.graph.wordlist:body.treatment", kind: "prop", name: Some("treatment") }
1 1
{
2 2
  "$type": "com.atproto.lexicon.schema",
3 3
  "defs": {
4 4
    "main": {
5 5
      "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.",
6 6
      "key": "tid",
7 7
      "record": {
8 8
        "properties": {
9 9
          "createdAt": {
10 10
            "description": "When this list was created",
11 11
            "format": "datetime",
12 12
            "type": "string"
13 13
          },
14 14
          "description": {
15 15
            "description": "Optional description of what this list covers",
16 16
            "maxLength": 300,
17 17
            "type": "string"
18 18
          },
19 19
          "enabled": {
20 20
            "default": false,
21 21
            "description": "Whether this list is currently active. Scheduling and spell effects further gate an enabled list.",
22 22
            "type": "boolean"
23 23
          },
24 24
          "name": {
25 25
            "description": "Display name for this word list",
26 26
            "maxLength": 64,
27 27
            "type": "string"
28 28
          },
29 29
          "schedule": {
30 30
            "description": "Optional active window. Absent means the list applies at all times while enabled.",
31 31
            "ref": "#schedule",
32 32
            "type": "ref"
33 33
          },
34 34
          "source": {
35 35
            "ref": "#source",
36 36
            "type": "ref"
37 37
          },
38 38
          "strength": {
39 -
            "description": "Mute strength percentage: the share of matching posts this list mutes (deterministic per post). Absent means 100 (mute everything it matches).",
39 +
            "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).",
40 40
            "maximum": 100,
41 41
            "minimum": 0,
42 42
            "type": "integer"
43 43
          },
44 44
          "syncToBluesky": {
45 45
            "default": false,
46 46
            "description": "Whether this list's words are also projected into Bluesky's native mutedWordsPref (managed entries, removed when the list is disabled or deleted).",
47 47
            "type": "boolean"
48 48
          },
49 49
          "targetFeeds": {
50 50
            "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.",
51 51
            "items": {
52 52
              "maxLength": 512,
53 53
              "type": "string"
54 54
            },
55 55
            "maxLength": 50,
56 56
            "type": "array"
57 57
          },
58 +
          "treatment": {
59 +
            "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.",
60 +
            "knownValues": [
61 +
              "hide",
62 +
              "warn",
63 +
              "show"
64 +
            ],
65 +
            "type": "string"
66 +
          },
58 67
          "updatedAt": {
59 68
            "description": "When this list was last modified",
60 69
            "format": "datetime",
61 70
            "type": "string"
62 71
          },
63 72
          "words": {
64 73
            "description": "The muted words/phrases in this list",
65 74
            "items": {
66 75
              "ref": "#word",
67 76
              "type": "ref"
68 77
            },
69 78
            "maxLength": 500,
70 79
            "type": "array"
71 80
          }
72 81
        },
73 82
        "required": [
74 83
          "name",
75 84
          "words",
76 85
          "createdAt"
77 86
        ],
78 87
        "type": "object"
79 88
      },
80 89
      "type": "record"
81 90
    },
82 91
    "schedule": {
83 -
      "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.",
92 +
      "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).",
84 93
      "properties": {
85 94
        "days": {
86 95
          "description": "Days of week the list is active (0 = Sunday … 6 = Saturday)",
87 96
          "items": {
88 97
            "maximum": 6,
89 98
            "minimum": 0,
90 99
            "type": "integer"
91 100
          },
92 101
          "maxLength": 7,
93 102
          "type": "array"
94 103
        },
95 104
        "endTime": {
96 105
          "description": "Window end as 'HH:MM' local time",
97 106
          "maxLength": 5,
98 107
          "type": "string"
99 108
        },
100 109
        "startTime": {
101 110
          "description": "Window start as 'HH:MM' local time",
102 111
          "maxLength": 5,
103 112
          "type": "string"
104 113
        }
105 114
      },
106 115
      "type": "object"
107 116
    },
108 117
    "source": {
109 118
      "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.",
110 119
      "properties": {
111 120
        "originalDid": {
112 121
          "description": "DID of the user this list was saved from.",
113 122
          "format": "did",
114 123
          "type": "string"
115 124
        },
116 125
        "originalUri": {
117 126
          "description": "AT URI of the list this copy was saved from (its immediate parent).",
118 127
          "format": "at-uri",
119 128
          "type": "string"
120 129
        },
121 130
        "rootDid": {
122 131
          "description": "DID of the original author at the top of the lineage.",
123 132
          "format": "did",
124 133
          "type": "string"
125 134
        },
126 135
        "rootUri": {
127 136
          "description": "AT URI of the first author's list — the top of the lineage — propagated to every descendant.",
128 137
          "format": "at-uri",
129 138
          "type": "string"
130 139
        },
131 140
        "type": {
132 141
          "knownValues": [
133 142
            "original",
134 143
            "learned"
135 144
          ],
136 145
          "type": "string"
137 146
        }
138 147
      },
139 148
      "type": "object"
140 149
    },
141 150
    "word": {
142 151
      "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.",
143 152
      "properties": {
144 153
        "actorTarget": {
145 154
          "description": "Whose posts to apply this word to. Absent means 'all'.",
146 155
          "knownValues": [
147 156
            "all",
148 157
            "exclude-following"
149 158
          ],
150 159
          "type": "string"
151 160
        },
152 161
        "targets": {
153 162
          "description": "What to match against: post text ('content') and/or hashtags ('tag'). Absent means both.",
154 163
          "items": {
155 164
            "knownValues": [
156 165
              "content",
157 166
              "tag"
158 167
            ],
159 168
            "type": "string"
160 169
          },
161 170
          "type": "array"
162 171
        },
163 172
        "value": {
164 173
          "description": "The word or phrase to mute",
165 174
          "maxLength": 100,
166 175
          "type": "string"
167 176
        }
168 177
      },
169 178
      "required": [
170 179
        "value"
171 180
      ],
172 181
      "type": "object"
173 182
    }
174 183
  },
175 184
  "id": "net.anisota.graph.wordlist",
176 185
  "lexicon": 1
177 186
}

Compare Other Versions

Lexicon Garden

@