nikclayton

Tusky

Edit to add this set of links to the posts in the series


That was an interesting 24 hours or so.

First of all, if you're one of many people who boosted or commented on the original post, or left feedback appreciating any of the open source work I have done, thank you.

After the project's financial admins shutdown discussion I spent some time reassessing my concerns, making a gut-check they seemed valid. It's still a risk to bring these sorts of issues to a public forum, and I'm relieved so many of the replies and commentary I've seen elsewhere agrees that yes, this is something to be concerned about.

I said I'd collate responses to issues I'd seen raised and reply in a single post, so that's this. I'm aware it's not an ideal format, but neither is fitting each reply in to multiple 500-character posts and hoping they federate properly so everyone sees the full discussion either.

If I've missed something below please feel free to send me a DM and I'll follow up in the next update (I'm pretty certain there'll be one, if only to announce a new git repository...)


Thank you for posting this. It is indeed concerning.

Whatever you do in the future, please consider not creating your own legal entity but instead joining one of the existing (well respected) fiscal host organizations like Software Freedom Conservancy, Software in the Public Interest, etc. They can handle all of the assets, legal paperwork, liability, etc. - https://mastodon.km6g.us/@kevin/110963590931224115

Yes, that's a very important point, thanks for raising it.

To organise my thoughts about this I started framing them as pitch for a new association. The early draft is pitch.md.

There's a great deal of overlap between what I describe there and the work other organisations do, and I would prefer to work with an existing organisation than contribute to further fragmentation.

I have already contacted

After some research those seemed to be the most appropriate three, but I may have missed some, so if you, or anyone else, can recommend other organisations that would be a good fit I'd be happy to hear it.


so, to summarize, you found a payment to a contractor suspicious because you couldn't find any code from the work, and then you talked to the contractor and found the code, so your suspicions were in fact unfounded.

And also you think it's a conflict of interest for the person who does the accounting for the org to also be on the payroll for he org... like an accountant - https://social.coop/@datatitian/110964853363902591

I see several other people have already replied to you correcting the inaccurate summary in your first paragraph.

Re the second, an accountant does not generally have sole approval authority over expenses. Consider this hypothetical. A financial admin drawing significant funds from the project receives a funding proposal from someone else. Approving this proposal would reduce the amount of money available for them, so they decide to reject the proposal.

There's the conflict.


I am not certain that the first two counts are suspicious. Payment was made for work on three issues. It sounds like the person was legit, they just didn't finish the work after being paid?

The second is just silly. Project Management is a job title and job description. It is explicitly what they mean by “someone unfamiliar with your project” will recognize.

Invoices don't list specifics. There should be internal docs for that. Those docs often aren't public.

If the project (hypothetically) hired me, I'd appear on the invoice as “Policy & Regulatory Analysis”. You would NOT list the different policy issues involved on the invoice. That would be documented internally for many reasons. What the accountants need to know is “what was this money used for?”

I do not work on IT regs, so I cannot speak to specifics, but I do think that it's better to ask an attorney or accountant to look first before raising suspicions. - https://med-mastodon.com/@UncivilServant/110964976957986119

It's not “didn't finish the work”, it's “didn't do the work”. The payee may have worked on the issues in private. But if they don't push the work somewhere public, create PRs from it, link to it, etc, then it is indistinguishable from not doing the work.

As I wrote in the initial post, there was no public indication any work had been done on these issues.

In your “Policy & Regulatory Analysis” example, as an open source project, I would expect to see, at minimum, a link to the work you produced as part of that analysis. That would be “sufficient detail to make it clear what the collective is paying for”, per the OpenCollective guidelines.

I would also expect any agreements the project makes with third parties to clearly set out what the expected deliverables are.

This works even for problems where the shape of the solution is not known beforehand.

For example a bad agreement would be “Solve problem X”. After a month the payee comes back and says “Sorry, I tried lots of things, I couldn't solve it, I've got nothing to show for it, here's my invoice.”

A better agreement would be “Solve problem X. If you can't solve X, deliver detailed descriptions of the approaches you took and why they don't work, so future attempts to solve this problem can build on what you learned.”


That's a lot of book keeping and managing overhead tbh. [...]

My greatest fear of launching monetary-focused foss products is this management overhead which compared to the rest of the industry just feels so unworthy. The monetary incentives just don't add up so I can definitely see how easy it'd be to get lost here. - https://fosstodon.org/@wraptile/110965923454931957

Yes, I agree. Introducing expenses, payments, grants, etc in to a project can add a lot of overhead.

Projects should not do this unless they have the necessary people, time, and expertise to do this properly.

In other words, don't adopt processes you're not staffed to meet (a variant of a rule I described in Rules for a healthy on-call rotation as “Don't set SLOs you are not staffed to meet”).


You’re expecting the financial admins to do their work for free. If anything, you’re making yourself look bad here, and not the Open Collective. - https://eupolicy.social/@whvholst/110965996322449276

I'm definitely not expecting someone to work for free. If the only way someone can contribute to an open source project is to be paid, and the project has funds to pay them that's absolutely fine.

That does not absolve them of the responsibility to do things properly, and with accountability.


Finally, this thread:

I've said this in the past, but maybe today it's more important than it's been in a very long time to tell you.

Thank you everyone who's been supporting #Tusky over the years on open collective. You've been supporting my disabled ass through so much, and I always knew I had a little bit of money at the end of the month, even when I was the most sick. ($100 when sick, $175 when able to work)

Me and Conny worked out this agreement back sometime after I started the open collective for the project (early 2019?). I've mostly been providing support, and project managment at some points. Organizing people and texts. A lot of invisible work. . I'll always be eternally grateful for everything you've done for us and me. - https://rage.love/@maloki/110969436075202543

If this shit turns out to be a techbro devaluing the invaluable (and largely taken on by women) glue work Yet Again I will yeet my chair through my office window. - https://comicscamp.club/@nebulos/110969752596667389 (direct link broken at request of the original poster)

i mean it partially is. - https://rage.love/@maloki/110969756892267642

It really partially isn't.

I was careful in my original post not to name anyone directly, I was expecting a collective response from the Tusky project. Since Maloki has come forward in public I won't anonymise comments from her in the future. I will continue to redact the names of anyone else in the project unless they also respond separately from the project.

Having dealt with that, there's quite a lot to unpack here.

First, @maloki@rage.love is the financial admin quoted in the original post, who initially insisted the discussion be shut down, and as is apparent from these posts, also the recipient of a substantial fraction of the project's funds.

That conflict of interest should be noted.

Second, an uncharitable reading of this thread — and while I continue to assume these issues were mistakes and not a deliberate attempt to hide wrongdoing, the needle on that dial is starting to wobble — could see this as an attempt to derail this conversation away from the concerns I raised, DARVOing the discussion.

Let's not do that, please.

Third, I think a reasonable reading of “$100 when sick, $175 when able to work” is the project was paying you during months when you did no work.

That seems to be supported by invoices like #30003, “Sick-pay June-December”.

If that's a mis-read of that line I'm happy to be corrected.

If that's not a mis-read then I have a host of other questions, starting with, was the project effectively paying you a salary as an employee?

I believe you're in the UK, so even if you think you were an independent contractor, IR35 probably applies (not an accountant, but I used to run a contractor business in the UK, so I have experience with this) and this probably should have been treated as employment income.

  • Was that legal?
  • Was the project paying you at least minimum wage (GBP 10.42 an hour)
  • Was the project paying appropriate taxes and employee insurance contributions?
  • Does the project have an employee-like arrangement with anyone else?
  • Why wasn't the process for using OpenCollective to pay employees (Employment & Benefits – Open Collective Foundation) followed?

Fourth, your comment “sometime after I started the open collective for the project” prompted me to go and look at those first invoices, at Tusky · Expenses – Open Collective

Of the eight invoices on that page. two are for Tusky project expenses (domain name, stickers), one is payment to a translator, for a total of USD 129.53. The rest (USD 960) are payments to you.

An uncharitable person could think the project did not actually need the funds, and that you started the project's OpenCollective to provide a front that would allow you to collect money hoping that it wouldn't be noticed.

A charitable person could assume that is not the case, but still agree that the optics of this are terrible, especially after you repeatedly tried to shut down any discussion of the project's invoices.

Fifth, “I've mostly been providing support, and project managment at some points. Organizing people and texts. A lot of invisible work”.

Undervaluing people's contributions is an ongoing issue, and a bit of a hot-button topic. If you're new to this I recommend Being Glue — No Idea Blog.

So let me make a couple of hopefully non-controversial statements:

  1. A quid pro quo for taking money from the project for “invisible” work is it's on you to make sure the work becomes visible.

  2. If you can't describe what you're doing for the project, how is the project going to replace you when you step down?

I know what that work looks like (I'm aware of the “invisible” / “looks like” irony), I've spent years in previous roles doing project management work, I've had the good fortune to be mentored by some truly excellent project managers, and I've worked to get people successfully promoted by ensuring that the impact of their glue work was recognised.

And I've had the opportunity to learn from some epic screw ups of my own.

So here's a short list of things you could have held yourself accountable for doing:

  • Curating the list of open project issues (as in #3240 for example)
    • Following up on incomplete bug reports
    • Checking if new releases solved the reporter's problem
    • Making sure that bug reports were not being ignored
    • Applying consistent labels to make them easy to manage
  • Improving the onboarding experience for new contributors
  • Planning a release calendar, or any form of release scheduling
  • Writing the release notes for each release
  • Proactively adding new contributors to the GitHub repo
  • Finalising a complete expense policy
  • Finalising a handover document to prepare for your departure (document promised since early 2023)
  • Following up on stalled PRs
    • Had the submitter run out of time?
    • Did they not understand the review feedback?
    • Were they waiting for review and the project had slipped up?
  • Creating GitHub issues to track problems reported by users to the @tusky account
  • Communicating the state of ongoing activities to the rest of the project contributors
  • Tracking requests for comments on proposal documents
  • Liaising between the Tusky project and other Fediverse projects
    • I'm aware of your overlap with the GoToSocial project. You seemed actively hostile to any communication with the folks at Mastodon GmbH.
  • Outreach to sites comparing different Mastodon clients, ensuring their info about Tusky was accurate
  • Keeping the OpenCollective page up to date with project news
    • I asked for this multiple times — it could have been as simple as copying the release notes in to an announcement after each release.
  • Regular check-ins with each contributor to the project; how are they doing, do they have the support they need, do they have any issues that need addressing, etc
  • Responding to inaccurate or mistaken reviews on Google Play

Not all of these things were being done by the project, but the ones that were were all being done by other people. Framing your contributions as non-specific “providing support, and project managment at some points. Organizing people and texts. A lot of invisible work.” is a very effective way for other people to get the impression that you must have been involved in these things, denying the credit to the people who were actually doing the work.

I'm not for the moment suggesting you have to do all of these things. But doing one or two of them effectively would have reduced the burden on other project contributors who weren't, it seems, being paid a salary.

I'll also highlight the distinction between being accountable for something and being responsible for something.

  • Accountable – I will make sure this gets done, I will find the right people to do it
  • Responsible – I will be the person actually doing the work

You may not have been the person who could be responsible for a piece of work, but you could have been the person who was accountable for a piece of work.

The concrete things I think you did in the 8 months I was involved (often after you were prompted to do them) were:

  • Creating chat rooms
  • Organising and chairing the first team meeting (after multiple people called for one to happen)
    • Subsequent team meetings were completely handled by [redacted], who scheduled them, managed the agenda, and chaired the meetings
    • That was helpful, the first meeting was run well, and [redacted] is continuing to do an excellent job
  • When @connyduck's private message stepping down from the project was leaked I suggested the project post an announcement, and posted a draft for discussion. You wrote your own announcement and posted that, also updating OpenCollective for the first time in more than four years.
  • Occasional comments on the chat groups or on discussion documents, no different from any other contributor.
  • An attempt to form a more formal support group with [redacted] that, to the best of my knowledge, didn't achieve anything

You may also have been doing some customer support from the @tusky account at some point before early 2023. It's difficult to tell because we didn't indicate who was making each post from the account. I'm confident you did very little, or none of that, from the time that I was also posting from the account, because I would have seen it.

Sixth, most of this is the project's problem. If the agreement (can we see it?) did not state what you were expected to do beyond vague “project management” then it becomes a lot more difficult for the project to say “hey, please can you do some of the things you're being paid to do”.

But recognising that issue, and working to correct it is a responsibility I would expect you to share.

And trying to shut down any discussion is still a terrible look.

Prompted by the questions in https://hhmx.de/@nick/16376, the answer's too long to fit in a post.

Doing some monitoring how a original #Mastodon server responds, i never (!) saw the described link header! The response may include no link header or a header like this: Link: ; rel=“next”, ; rel=“prev”

You should get a Link header from any API response that returns a page of data, like https://docs.joinmastodon.org/methods/notifications/#get.

[Almost; in testing this I just discovered an edge case, which I've reported as a bug at https://github.com/mastodon/mastodon/issues/25495]

An API response for a single item, like https://docs.joinmastodon.org/methods/notifications/#get-one won't include the Link header.

I just tested this with https://restfox.dev against my mastodon.social account (https://github.com/tuskyapp/Tusky/pull/3610/files?short_path=00c65c2#diff-00c65c2349f395f9f9b78b0fe84d3638b78f3ef4abf98294364b5c4d0ef32473 has details on how to do this).

On my research i saw something in the #Tusky source, that looks like Tusky as clients seems to generate a link header? If so, why?

https://github.com/tuskyapp/Tusky/blob/develop/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationsPagingSource.kt#L107-L178

That function needs to return a page of results as an HTTP Response. The code that calls that function unpacks the Response and parses the contents of the Link header, so the header must be present.

To figure out what page of results to return one of the parameters to getInitialPage is the ID of the item (in this case, a notification) that should be at the start of the page. This is the params.key value.

The Mastodon API lets you make requests like “Get me the page immediately after ID X” or “Get me the page immediately before ID X”.

But it does not let you make a request “Get me the page that includes key X”.

So the code has to do that itself, starting around line 134. It does this by making two API calls. One to retrieve the notification with ID X, and one to retrieve the notifications immediately after that.

If those calls succeed the code has two values to operate on; the notification, and the page of notifications immediately after it.

Remember that this function needs to return a single page of notifications. So it creates a fake page which contains both values. This fake page needs a Link header (because the code that calls this code expects a Link header).

So that's why it constructs one in this case.

This code is only called to get the first (or initial) page to show the user. After that the pages above and below are loaded with single calls to the Mastodon API, and return the Link header without any alterations.

Besides of details, if the header should be named “Link:” or “link:“,

HTTP headers are case-insensitive (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers) so you can use either.

Tusky 22 now sometimes reports an array index out of range (-1) or similar (taking this from my memory, for exact message, i have to check it again).

That would be a bug, a detailed report with reproduction steps would be appreciated.

During development i also saw Tusky sending requests for notifications in an endless loop... wondered why.

I suspect the min_id / max_id handling in your server is not correct.

And... could someone clarify the difference between sinceid and minid? If Mastodon will handle this differently?

sinceid = String. Return results newer than this ID minid = String. Return results immediately newer than this ID

What should be the difference between “newer” and “immediately newer”?

Suppose the user has 10 notifications, numbered 1 through 10.

  1 2 3 4 5 6 7 8 9 10
  ^                 ^
  |                 |
oldest            newest

They make the request:

/api/v1/notifications?since_id=5&limit=2

This means they want two (limit=2) notifications that are newer than notification 5 (since_id=5).

The server returns notifications 9 and 10, as these are the two newest notifications.

Think of since_id as “Start at the newest notification, count backwards limit notifications, and return from there”.

Same setup, but the request is now:

/api/v1/notifications?min_id=5&limit=2

This means they want two (limit=2) notifications that are immediately newer than notification 5 (min_id=5).

The server returns notifications 6 and 7, as these are the two notifications immediately newer than 5.

Think of min_id as “Start at min_id, then return the next limit notifications”.

Given that min_id was added to the API after since_id was my working theory is that this was a design flaw in the API, which min_id fixed after the API was first released.