According to the comment in my code, it was Pleroma.
It is a Mastodon idiosyncrasy. As far as I know, no other implementation has this limitation.
According to the comment in my code, it was Pleroma.
It is a Mastodon idiosyncrasy. As far as I know, no other implementation has this limitation.
Is this not simply https://www.w3.org/ns/activitystreams#closed? Activity Vocabulary
Itâs rather awkward due to the range being described as a union of Object, Link, xsd:dateTime, and xsd:boolean⊠but it is a property defined by AS2 I guess. And in the context document, the term definition for closed says that itâs specifically a datetime: as:closed is wrongly defined in the normative context as only being xsd:datetime · Issue #542 · w3c/activitystreams · GitHub
So the least problematic usage of it right now is to use closed as âthe datetime when the Question was closedâ. (It could possibly be applied to more than just Question as well, which Expand the domain of `closed` to be applicable to more than just `Question`? · Issue #594 · w3c/activitystreams · GitHub explores, but in the context of this FEP this shouldnât be an issue.)
Technically the initial implementation of polls was entirely a Mastodon idiosyncracy, although ostensibly based on a non-normative example from AS2-Vocab regarding how one might use Question: Activity Vocabulary
Note that in the same section, there are multiple ways to use Question, not limited strictly to polls. By default, a Question is open-ended, and you could liken them to StackOverflow posts or Tumblr asks. Mastodon assumes that oneOf/anyOf is what makes it a âpollâ, although the matching of a âpoll responseâ to a âpoll optionâ is pretty weird and involves a sort of name-based indexing or possibly an identity-by-description (not using id). The reason Mastodon polls donât support image attachments is partly because Mastodon was unsure how to deal with poll responses referencing those image attachments, and partly because Mastodonâs UX makes it awkward to stuff images into poll options without affordances like expanding the image or having multiple representations of an image.
Aside from UX concerns, there are protocol concerns with possibly invalidating all previous votes if something about the image attachment(s) is different.
I think the FEP covers a lot of the history and contrast with intended usage, although it doesnât fully cover the oddities and idiosyncracies when discussing requirements.
inReplyTo the Question, but somehow ends up in the replies of the poll options indirectly? (via replies.totalItems on each option)
replies.totalItems is already pretty weird and imprecise too⊠in a cleaner re-implementation it would probably make more sense to just have a :voteCount on the option itself.@silverpill One suggested correction to the FEP:
Questionobjects MAY have anendTimeproperty indicating the time when the poll ends. Some implementations useclosedproperty instead ofendTimeor in addition to it (even if the poll is open). Consumers MUST processclosedin the same way asendTime.
endTime is when the poll ends, but closed is when the poll closed. They are not the same. A poll with endTime but no closed is by default still open. A poll with closed is closed. I think the logical equivalence youâre looking for is when endTime is in the past, you can maybe infer that the poll closed at that same time?
Also would it make sense to mention Mastodonâs extension properties? http://joinmastodon.org/ns#votersCount in particular is used to disambiguate participation statistics for multiple-choice polls (anyOf). A poll with 3 options that has 5, 7, and 8 votes out of 10 total participants would show percentages of 50%, 70%, and 80% (instead of 25%, 35%, and 40%).
Other feedback:
type of Note specifically and nothing else. Mastodon serializers will publish this, but itâs not required or used in any way during consumption. Similar for Collection as the type of the replies.content property.â Why not? I assume itâs to differentiate it from a âpostâ, but thereâs no conflict if the same thing is both a vote and a post.
inReplyTo. Itâs just that votes use name and posts use content (although they can also use name).Do you know any fedi platform that allows closing a poll before the end time? From what I saw, closed is always redundant.
Yes, I probably should mention it, but I donât understand how it is used. So it affects the displayed percentages in Mastodon? How they are calculated? Why would they want percentages to not add up to 100%?
Other implementations might expect Note, so I donât recommend changing the type.
I think they should be disjoint. I doubt that any implementation allows votes with comments.
I agree. This should be not a requirement, but a description: âthis activity is not delivered to anyone else.â
As far as I know, the implementation of a poll described in this FEP does not allow changing votes. Alternative implementations could be mentioned to the âFuture workâ section.
@trwnh Do you know if Mastodon puts a limit on the number of poll options in incoming polls? I tried to find it in the code but couldnât.
It seems to be 500 poll options, as of v4.5.5 / v4.4.12 / v4.3.18.
As best as I can tell, the initial PR describes local limits of 4 options and 25 characters per option. There was some talk of enforcing remote limits of 10 options, but I donât think that ever got implemented. I have definitely seen polls with over 20 options from my Mastodon account. The local limits were later raised in https://github.com/mastodon/mastodon/pull/13257 to 50 characters per option. The current local validators are located at https://github.com/mastodon/mastodon/blob/bdad4f78f309af6ac439dac4f7705818550e7c08/app/validators/poll_options_validator.rb and https://github.com/mastodon/mastodon/blob/bdad4f78f309af6ac439dac4f7705818550e7c08/app/validators/poll_expiration_validator.rb.
Incoming polls pass through the Create handlerâs process_poll function which validates the poll by attempting to parse it successfully. The poll parser contains all the logic for parsing incoming polls, as far as I can tell. There is a line declaring MAX_ITEMS = 500 which git blame attributes to Merge commit from fork · mastodon/mastodon@028e76f · GitHub and seems to be present in mastodon/FEDERATION.md at bdad4f78f309af6ac439dac4f7705818550e7c08 · mastodon/mastodon · GitHub as well. Looking through release changelogs, I found Denial of Service from a single post (client/server) · Advisory · mastodon/mastodon · GitHub which describes a DoS from trying to process too many poll options.
My view is that since both are optional, it may be that a poll had no specific endTime but was later closed manually. Or the poll may be temporarily closed before the endTime has been reached. It seems like a good practice to explicitly mark when the poll is closed instead of having people assume it from endTime being in the past. If I am interested in knowing whether the poll is closed or not, I am not necessarily interested in the exact endTime. You could even have a situation where when the poll ends, endTime is replaced by closed.
(This isnât to say that endTime implies the poll is still open, but that it implies different things depending on whether it is in the past or the future relative to the current time â kind of like the predicates âgrueâ and âbleenâ, if youâre familiar with that problem. TLDR: âgrueâ is equivalent to green before time t, and equivalent to blue after time t. The perceived color might change, but it is always âgrueâ independent of time. In much the same way, the poll is âopenâ before t == endTime and âclosedâ after t == endTime.)
(And this isnât even getting into clock skewâŠ)
The multiple choice âanyOfâ poll inherently allows people to select multiple options. This means that the total number of options selected isnât always relevant; whatâs relevant is how many people selected which option. So to contextualize the raw numbers, you donât say â25% of the votes went to option Aâ, you say â50% of the voters approved of option Aâ. You canât calculate these percentages without knowing the total number of voters (as distinct from the total number of votes).
Basically, if the poll is multiple choice (uses as:anyOf), then Mastodon will use the toot:votersCount to calculate the percentages. If the poll is single choice (uses as:oneOf), then you could infer the voter count from the vote count, since you assume each voter only voted for 1 option. Or you could just use the vote count directly, under the same assumption. The assumption doesnât hold when voters are allowed to vote for more than 1 option.
Other implementations might expect
Note, so I donât recommend changing the type.
I think they should be disjoint. I doubt that any implementation allows votes with comments.
I havenât surveyed what any particular implementation does, but I would not recommend consumers to attempt to validate that a poll response is a Note. There might not be any particular harm in publishers saying that a poll response is a Note, but it would be very unfortunate if everyone was forced to say this. In reality, if we had a PollVote or Answer or similar class, we would probably use that. Even more compelling, if we were trying to not confuse a Note with a PollVote for whatever reason. (I still see no reason to disallow this, since the comment/content can be ignored when tallying up vote counts. The thing that makes it a vote in this mechanism is inReplyTo + name.)
So to contextualize the raw numbers, you donât say â25% of the votes went to option Aâ, you say â50% of the voters approved of option Aâ.
In my view, counting votes is also a reasonable thing to do. You seem to be saying that the only correct presentation is where voters are counted. Why?
Basically, if the poll is multiple choice (uses as:anyOf), then Mastodon will use the toot:votersCount to calculate the percentages.
What happens if votersCount property is not present?
In my view, counting votes is also a reasonable thing to do. You seem to be saying that the only correct presentation is where voters are counted. Why?
Counting votes is reasonable, but counting voters is also reasonable if you are trying to poll voters (e.g. âwhich options do you approve ofâ) as opposed to polling options (e.g. âwhich option is most popularâ)
In a poll with 3 options, each getting 1 vote from 3 voters, are you interested in knowing that each option got 33% of the votes, or that each option was approved of by 1/3 of the voters? In this case, itâs the same, because 1 voter = 1 vote. But if you allow multiple votes per voter, then you get different numbers per vote vs per voter. Same poll with 3 options, say it gets 3 voters, except option 1 gets approval of all 3 voters, option 2 gets approval of 2 voters, and option 3 gets approval of no voters. So the result is that 3 voters cast 5 votes, and option 1 got 100% of the voters despite only getting 60% of the votes, and option 2 got 66.6% of the voters while getting 40% of the votes. Seeing that option 1 got 60% while option 2 got 40%, how do you interpret that? Compare to seeing that option 1 got 100% of the voters; how do you interpret that?
anyOf polls tend to favor voters more than votes, and oneOf polls nominally donât make a difference because 1 voter = 1 vote.
What happens if
votersCountproperty is not present?
Mastodon will always include votersCount, but if it is missing then they fall back to counting vote percentages instead of voter percentages (at the cost of them being potentially less useful, but itâs all they can do).
Thanks for the info @trwnh
I am updating the FEP: https://codeberg.org/fediverse/fep/pulls/842. There are new sections about votersCount, closing polls and Mastodonâs limits.
I would not recommend consumers to attempt to validate that a poll response is a Note
I agree that it is better to implement polls in forward compatible way. However, the FEP doesnât strictly require type to be Note, so implementers are free to use other heuristics. Maybe something could be said about alternate types in the âFuture workâ sectionâŠ
P.S.
I believe the documentation of Poll.voters_count is incorrect:
Type:
nullable| Integer, or null ifmultipleis false.
In reality, the value may be present even if multiple is true. It is only null if voters count is not known (in that case Mastodon shows âN votesâ instead of âN peopleâ).
Right now most polls are just a question with multiple answers and the sum of the amount of accounts which have broadcast against a one or more answers.
so âPollsâ is more of a âvibe checkâ⊠such as âRed VS Blue?â or âparma vs parmiâ for the Australians.
as this doesnât account for (in mastodon at least) being able for
followers-only but voters-only).Random example: Who wants to come to my birthday party? What days are you available for a meeting? (monday,wednesday,friday), Who wants a sticker of this dinosaur on a BMX bike?.. these kind of engagement polls donât work with with closed polls as default.
Question: Is there any interest in open vs closed polls vs mixed?
Side Question: Visibility into polls makes sense if actors were interested in removing people from the poll who were using bots to mess/skew with the poll⊠not that polls should be considered âstatically reliantâ.
Sounds good, I think we can add this. Perhaps to the âFuture workâ section, if there are no implementers by the time the FEP will have been finalized.
Iâm also planning to introduce the voters collection, which is necessary for addressing Update activities. Usually, the poll author sends these activities not only to followers, but also to voters. However, this is not currently reflected in the activity attributes.
So finally. After releasing my WordPress Polls for ActivityPub plugin (link will be working in the next days, Source Code) I find some time.
updated: I am unsure, I would maybe love to have both information: when has either the question/poll-type/option/or start and endTime been last updated, and when has the last vote been received. For me the former is the more important information. What does Mastodon actually do?endTime is present and closed is true, should the endTime be able to serve as a âclosed timeâ? I think this could be written more precisely, I encourage not to be afraid to just use a MUST here because itâs something easy to implement and I guess will never be a blocking issue for someone to implement it.anyOf or oneOf options and setting the votersCount to 0.updated property: Why not make this a MUST? I see no reason not to.Addition 2026-06-26:
- I would like to see a general notice, maybe in the summary, that this FEP is only covering text based polls and is not intending to cover other things, like image polls, or should it?
What is the difference between a text-based poll and image poll?
- Maybe the history section could add a conclusion sentence what this FEP is aiming to do: writing guides about how to implement polls so that we have a common denominator about the way polls are currently handled widely in the Fediverse due to early implementations by Mastodon? (⊠okey, this sentence was bad).
Yes, I will add a sentence.
- Voters count: I would argue that this should be change to a MUST (the current âcanâ is ambiguous anyway), at least for multiple choice polls, because otherwise remote applications have no way of showing correct percentages of the results.
I am not convinced that the percentages adjusted by votersCount are more correct than non-adjusted, which is why the word âcanâ is used instead of âMUSTâ.
Personally, I prefer non-adjusted.
- Receiving a vote: What I see missing is a validation/verification that an actor has not voted already. Or is the argument: a remote server that can construct arbitrary idâs could also construct arbitrary actors?
Itâs missing. Iâll fix that in the next revision.
- Another open question for me is: what is about receiving deletes or updates on votes? I think a short guidance would be helpful for new implementers. Should we ignore, Delete or Updates on âvote repliesâ? Should we indicate that we do?
To be honest, I donât know how to handle these activities. Itâs probably better to leave it as an open question.
- Updating
updated: I am unsure, I would maybe love to have both information: when has either the question/poll-type/option/or start and endTime been last updated, and when has the last vote been received. For me the former is the more important information. What does Mastodon actually do?
I am not aware of any polls implementation that exposes this information. Maybe startTime could be used to indicate when the poll was resetâŠ
- Publishing results I advice to remote the MUST here. I even ask myself whether we should remove sending updates on incoming votes completely. Cause every remote application that received a vote can define itâs own refresh cycles.
We can change it to âWhen actor that published a poll receives a vote, it MAY publish an Update activityâ, but also add âit MUST publish an Update activity when the poll is closedâ.
- Closing a poll: so no boolean MUST be used on closed? Or if
endTimeis present andclosedistrue, should theendTimebe able to serve as a âclosed timeâ? I think this could be written more precisely, I encourage not to be afraid to just use a MUST here because itâs something easy to implement and I guess will never be a blocking issue for someone to implement it.
closed is optional. Not all implementations use it, and adding this property has a cost - a background task that updates Question objects might be necessary.
We can add âThe value MUST NOT be a booleanâ.
- Editing Options: I would be more precise: Post-Hum ignore of all previous receive vote replies, emptying all replies collection of all
anyOforoneOfoptions and setting thevotersCountto0.
Good idea, I will update this section.
- Question object â
updatedproperty: Why not make this a MUST? I see no reason not to.
If I remember correctly, there was a popular implementation that didnât add updated. The SHOULD was used because this FEP attempts to be compatible with existing implementations.
- Re-opening closed polls: This is something I would like to have guidance. Should a poll object keep track when being closed and re-opened again? Idea: if poll votes are not reset poll MUST keep the information when the poll was open and when not. Or say once a poll has been closed. Re-Opening causes the votes to reset?
I think re-opening should not reset the votes.
- Re-opening closed polls: When votes are reset should be sent Reject or Undo activities to already accepted votes? Or should we have a specific votesReset action or indicaiton in the updated object (so that remote server know, that their actors might vote again?!).
Good question. Maybe we should use startTime to signal resets, and require implementations to let users vote again if this value changes.
Regarding Publishing results, I agree with @andre about revising the MUST, since observing even the most prominent implementer, Poll Update activities did not happen/correspond to every vote, but every third vote (on a Poll with hundreds of votes)!
To allow for some implementation flexibility (scheduled vote count updates), while maintaining expected user interactions. I would revise to something like :
When the actor that published a poll receives a vote, it publishes an
Updateactivity containing theQuestionobject with updated results. Each vote activity responseMUSTbe immediately delivered to the actor that voted in the poll. This activitySHOULDpromptly be delivered to the audience of the poll and to every actor that voted in the poll.
Thatâs better, thanks for the suggestion. Iâll change the text.
Update: https://codeberg.org/fediverse/fep/pulls/879
I added several changes that we discussed here.