#58 Ticket categories

Open
opened 2 months ago by fr33domlover · 16 comments

We've discussed ticket categories (bug, task, feature request, etc.) and we mentioned 2 ways to represent them:

  1. As subtypes of the Ticket type
  2. As values to use with a dedicated separate property, e.g. we could call it ticketCategory

I was in favor of giving the 1st option a priority, to avoid having unnecessary duplication of the standard RDF type property, and @zPlus was in favor of the 2nd option (correct me if I'm wrong and feel free to comment on this).

Further research: Look at how these categories get used in existing software. For example I saw some ticket trackers that had a set of built-in categories on a side panel.

Feneas forum thread

We've discussed ticket categories (bug, task, feature request, etc.) and we mentioned 2 ways to represent them: 1. As *subtypes* of the `Ticket` type 2. As values to use with a dedicated separate property, e.g. we could call it `ticketCategory` I was in favor of giving the 1st option a priority, to avoid having unnecessary duplication of the standard RDF `type` property, and @zPlus was in favor of the 2nd option (correct me if I'm wrong and feel free to comment on this). Further research: Look at how these categories get used in existing software. For example I saw some ticket trackers that had a set of built-in categories on a side panel. [Feneas forum thread](https://talk.feneas.org/t/ticket-categories/193)
zPlus commented 2 months ago
Owner

After some research, the way this is done with RDF seems to be that Classes are used to represents things that we are actually reasoning about in our domain, and Properties for relations or actual literal properties. So I'm inclined to agree that 1. is a better approach.

If the issue tracker is supposed to be the most general definition possible however, it's worth noting that the domain is endless. In our own context of source code development we have bugs, feature requests, patch, etc. We can define subtypes for these. However if it ought to be reused for a particular context, for example for videogame players, I've seen issue trackers using very specific requests types such as "Quest X", "Final boss" "Hidden levels" and so forth. We cannot account for every use case of the issue tracker. That's why I'm torn between subtypes and something else like a "labels" property for instance.

After some research, the way this is done with RDF seems to be that Classes are used to represents things that we are actually reasoning about in our domain, and Properties for relations or actual literal properties. So I'm inclined to agree that 1. is a better approach. If the issue tracker is supposed to be the most general definition possible however, it's worth noting that the domain is endless. In our own context of source code development we have bugs, feature requests, patch, etc. We can define subtypes for these. However if it ought to be reused for a particular context, for example for videogame players, I've seen issue trackers using very specific requests types such as "Quest X", "Final boss" "Hidden levels" and so forth. We cannot account for every use case of the issue tracker. That's why I'm torn between subtypes and something else like a "labels" property for instance.
fr33domlover commented 2 months ago
Collaborator

Either way, we want stuff like "Final boss" to be possible. But people can do that using tags, it doesn't have to be the ticket's category. Even things like "feature" and "bug" can be just user defined tags, right? Am I observing correctly, that known subtypes of tickets matter only in the following cases:

  1. Display in the UI, i.e. different icons for bug/feature/etc. (although people could set icons for their custom tags, or use emoji in the tag labels)
  2. Different functionality, i.e. the actual software logic needs to determine which ticket subtype it is

Either way, it's an open world: If you use subtypes, people can add custom ones. If you use a dedicated property, you have to somehow let people add custom kinds of tickets, and then they can use that mechanism

So extensions like "Final Boss" are possible either way. What we can do is:

  • Require/suggest in the spec that Ticket is always specified as the type, in addition to any subtypes, to make sure plain-JSON implementations can determine that it's a ticket
  • Define standard ticket subtypes, if we need them
  • Make it clear that people can define more subtypes because it's open-world RDF

Some ticket trackers have a standard set of subtypes, some have an extensible one, some have only plain-text user defined tags. I'm hesitant to define a standard set of subtypes because there's no consensus about what they should be.

I once made a little to-do list app and after tons of research I came up with 7 standard kinds of tickets. But none of those 7 were software-specific, e.g. there was "problem" or "fault" etc. and not "bug" because the latter is a software-specific term.

There are also ticket trackers that have a "severity" and "priority" scales, and that's how they do this stuff.

IDEA: Let's decide that for now we define only subtypes that have distinct functionality needed for our spec. Otherwise, just use plain Ticket. We'll separately look into having a standard set of ticket subtypes, if we decide we want that.

How does that sound? :)

Either way, we want stuff like "Final boss" to be possible. But people can do that using tags, it doesn't have to be the ticket's category. Even things like "feature" and "bug" can be just user defined tags, right? Am I observing correctly, that known subtypes of tickets matter only in the following cases: 1. Display in the UI, i.e. different icons for bug/feature/etc. (although people could set icons for their custom tags, or use emoji in the tag labels) 2. Different functionality, i.e. the actual software logic needs to determine which ticket subtype it is Either way, it's an open world: If you use subtypes, people can add custom ones. If you use a dedicated property, you have to somehow let people add custom kinds of tickets, and then they can use *that* mechanism So extensions like "Final Boss" are possible either way. What we can do is: - Require/suggest in the spec that `Ticket` is always specified as the `type`, in addition to any subtypes, to make sure plain-JSON implementations can determine that it's a ticket - Define standard ticket subtypes, if we need them - Make it clear that people can define more subtypes because it's open-world RDF Some ticket trackers have a standard set of subtypes, some have an extensible one, some have only plain-text user defined tags. I'm hesitant to define a standard set of subtypes because there's no consensus about what they should be. I once made a little to-do list app and after tons of research I came up with 7 standard kinds of tickets. But none of those 7 were software-specific, e.g. there was "problem" or "fault" etc. and not "bug" because the latter is a software-specific term. There are also ticket trackers that have a "severity" and "priority" scales, and that's how they do this stuff. IDEA: Let's decide that for now we define only subtypes that have distinct functionality *needed for our spec*. Otherwise, just use plain `Ticket`. We'll separately look into having a standard set of ticket subtypes, if we decide we want that. How does that sound? :)

IDEA: Let's decide that for now we define only subtypes that have distinct functionality needed for our spec. Otherwise, just use plain Ticket. We'll separately look into having a standard set of ticket subtypes, if we decide we want that.

I agree, trying to define all possible types especially as object types is going to end up with missing some and then someone is unhappy. I'd say Ticket and only with strong reasons define other types. Let's keep things simple. There can always be a more flexible Subtype if need be.

> IDEA: Let's decide that for now we define only subtypes that have distinct functionality needed for our spec. Otherwise, just use plain Ticket. We'll separately look into having a standard set of ticket subtypes, if we decide we want that. I agree, trying to define all possible types *especially* as object types is going to end up with missing some and then someone is unhappy. I'd say `Ticket` and only with strong reasons define other types. Let's keep things simple. There can always be a more flexible `Subtype` if need be.
fr33domlover commented 2 months ago
Collaborator

@zPlus, what do you think about the proposal above?

@zPlus, what do you think about the proposal above?
zPlus commented 2 months ago
Owner

When I interact with an actor of type Tracker I know that the actor is something or somebody that is recording and following the progress of something (the issue). So if I Offer an object to the tracker, what I'm asking for is to track that object.

In practice this means that instead of Offering a Ticket like we are doing now, we could Offer a Note or a Patch or any other type of object that I (a Person in my case) have created. In response the Tracker can Accept it and provide the ID of a new Ticket that it has created.

Sounds good or sounds bad?

When I interact with an actor of type `Tracker` I know that the actor is something or somebody that is recording and following the progress of something (the issue). So if I `Offer` an object to the tracker, what I'm asking for is to track that object. In practice this means that instead of `Offer`ing a `Ticket` like we are doing now, we could `Offer` a `Note` or a `Patch` or any other type of object that I (a `Person` in my case) have created. In response the `Tracker` can `Accept` it and provide the ID of a new `Ticket` that **it** has created. Sounds good or sounds bad?
fr33domlover commented 2 months ago
Collaborator

In general in ActivityPub, there's no specific practical meaning for Offer. Actually, except for a few specific side effects that some activity types have, everything is open. The Offer activity just means an actor is offering something to someone, basically. Any extra meaning is up to us to define in ForgeFed.

And we can decide that when you Offer a Ticket, either to someone in general or specifically to an actor of some specific type, then the meaning is "I'm offering that you track this work item in your list of open work items". But that's specific to Ticket. Issue tracker generally don't track images or notes or places or idk what else, so to Offer those objects to an issue tracker doesn't make much sense in our context here. An issue tracker wouldn't know what to do with them.

We could use more verbose forms though, for example to Offer a Create or Add activity whose object is the ticket. But for now a simple Offer-a-ticket works and we can keep it simple.

In general in ActivityPub, there's no specific practical meaning for `Offer`. Actually, except for a few specific side effects that some activity types have, everything is open. The `Offer` activity just means an actor is offering something to someone, basically. Any extra meaning is up to us to define in ForgeFed. And we can decide that when you `Offer` a `Ticket`, either to someone in general or specifically to an actor of some specific type, then the meaning is "I'm offering that you track this work item in your list of open work items". But that's specific to `Ticket`. Issue tracker generally don't track images or notes or places or idk what else, so to `Offer` those objects to an issue tracker doesn't make much sense in our context here. An issue tracker wouldn't know what to do with them. We could use more verbose forms though, for example to `Offer` a `Create` or `Add` activity whose `object` is the ticket. But for now a simple Offer-a-ticket works and we can keep it simple.

I've got a little fever so might not be thinking straight. But why do we have the Offer at all? I would assume Create would be more normal.

I mean when you post something on a social network, you Create and send it to whoever might be interested. I would assume it to work the same way in Forgefed.

There has been discussion in the AP community at some point of returning a Reject for posted payloads that the receiver does not intend to process, for reason or another. An activity doesn't have to be an Offer for it to be rejected.

I've got a little fever so might not be thinking straight. But why do we have the `Offer` at all? I would assume `Create` would be more normal. I mean when you post something on a social network, you `Create` and send it to whoever might be interested. I would assume it to work the same way in Forgefed. There has been discussion in the AP community at some point of returning a `Reject` for posted payloads that the receiver does not intend to process, for reason or another. An activity doesn't have to be an `Offer` for it to be rejected.
fr33domlover commented 2 months ago
Collaborator

After lots of discussion, in the forum (possibly the old socialhub) and on IRC (#social), I decided to go with Offer because it much more clearly states the intention. When you Create something and intend to offer it to someone, how do you state that someone in the Create? A Create having a target is weird because you don't create stuff "to" someone. But you certainly offer something to someone. Create is also typically used for publishing stuff on your instance / under your user, while in our case the intention is to offer something to be hosted elsewhere.

People offered all kinds of alternative workflows for offering something to be created remotely. I like the Offer approach because it's simple plain in-band S2S, simple plain single standard activity. And clearly communicates what is offered (the object) and to whom (the target). And that it's being offered and not merely just published.

It's possible to first Create the ticket and then Offer it in a separate activity, but as long as there's no need for that, I prefer to go simple and just use Offer alone. The discussion happens around the project's side ticket anyway, so, right now there isn't much obvious benefit in doing a separate Create before the Offer.

After lots of discussion, in the forum (possibly the old socialhub) and on IRC (#social), I decided to go with `Offer` because it much more clearly states the intention. When you `Create` something and intend to offer it to someone, how do you state that someone in the `Create`? A `Create` having a `target` is weird because you don't create stuff "to" someone. But you certainly offer something to someone. `Create` is also typically used for publishing stuff on your instance / under your user, while in our case the intention is to offer something to be hosted *elsewhere*. People offered all kinds of alternative workflows for offering something to be created remotely. I like the `Offer` approach because it's simple plain in-band S2S, simple plain single standard activity. And clearly communicates what is offered (the `object`) and to whom (the `target`). And that it's being offered and not merely just published. It's possible to first `Create` the ticket and *then* `Offer` it in a separate activity, but as long as there's no need for that, I prefer to go simple and just use `Offer` alone. The discussion happens around the project's side ticket anyway, so, right now there isn't much obvious benefit in doing a separate `Create` before the `Offer`.

It's possible to first Create the ticket and then Offer it in a separate activity, but as long as there's no need for that, I prefer to go simple and just use Offer alone.

It's not simple, it's against how the current activitypub powered web works. Do you have an example where offer is used to create objects on any platform?

But more here. Which isn't really the right issue either :D Should open a new one or reopen an old one - preferences?

> It's possible to first Create the ticket and then Offer it in a separate activity, but as long as there's no need for that, I prefer to go simple and just use Offer alone. It's not simple, it's against how the current activitypub powered web works. Do you have an example where offer is used to create objects on any platform? But more [here](https://notabug.org/peers/forgefed/issues/7#issuecomment-17042). Which isn't really the right issue either :D Should open a new one or reopen an old one - preferences?
fr33domlover commented 2 months ago
Collaborator

Let's continue this discussion in #7 :) Like I said there, the current ActivityPub powered fediverse doesn't need this sort of stuff for the people-post-toots scenario. But the offer-objects-to-remote-actors scenario does exist in some AP implementations, and each one has their own way of doing it because there's no standard right now.

Let's continue this discussion in #7 :) Like I said there, the current ActivityPub powered fediverse doesn't need this sort of stuff for the people-post-toots scenario. But the offer-objects-to-remote-actors scenario does exist in some AP implementations, and each one has their own way of doing it because there's no standard right now.
zPlus commented 2 months ago
Owner

What do you guys think about this: when an actor A (for example me, a Person) Create a new Issue, they will sends the activity to an actor T. This means that A is notifying T that he's got some kind of issue. T will in turn Create a new Ticket containing a copy of the Issue.

@fr33domlover what do you say?

What do you guys think about this: when an actor A (for example me, a Person) `Create` a new `Issue`, they will sends the activity to an actor T. This means that A is notifying T that he's got some kind of issue. T will in turn `Create` a new `Ticket` containing a copy of the `Issue`. @fr33domlover what do you say?
fr33domlover commented 2 months ago
Collaborator

@zPlus, this is essentially the concept of approach 2 (i.e. create a copy) except using a Create activity like in approach 1, and another Create for the copy itself. My thoughts:

  • What's important is which approach we pick; the exact activity is a smaller issue to resolve (ugh those annoying puns are everywhere lol). I think in approach 2, Offer is better for 2 reasons: (1) it allows to separate the creation from the offering, and to offer something that you originally wrote only as a draft for yourself (and thus can't Create again since you already created it); (2) it allows to specify to whom you're offering; in Create you can address a thousand actors, how do we know who is the offer target? In Offer you can use the target property etc, while in Create it makes much less sense to create something "to" someone; Create is generally used for plainly publishing stuff (but if there are any arguments in favor of Create over Offer, I'd like to hear them :)
  • The Create that creates the copy, I don't have an opinion about it yet. I prefer that as long as we don't strictly need it for the spec (e.g. as a way to prove author authenticity), it stays optional. But it's a good point to remember!
@zPlus, this is essentially the concept of approach 2 (i.e. create a copy) except using a `Create` activity like in approach 1, and another `Create` for the copy itself. My thoughts: - What's important is which approach we pick; the exact activity is a smaller issue to resolve (ugh those annoying puns are everywhere lol). I think in approach 2, `Offer` is better for 2 reasons: **(1)** it allows to separate the creation from the offering, and to offer something that you originally wrote only as a draft for yourself (and thus can't `Create` again since you already created it); **(2)** it allows to specify to *whom* you're offering; in `Create` you can address a thousand actors, how do we know who is the offer target? In `Offer` you can use the `target` property etc, while in `Create` it makes much less sense to create something "to" someone; `Create` is generally used for plainly publishing stuff (but if there are any arguments in favor of `Create` over `Offer`, I'd like to hear them :) - The `Create` that creates the copy, I don't have an opinion about it yet. I prefer that as long as we don't strictly need it for the spec (e.g. as a way to prove author authenticity), it stays optional. But it's a good point to remember!
zPlus commented 1 month ago
Owner

@fr33domlover

Looking at "toots" on mastodon, they seem to work like this (unless I'm missing something):

  1. user 1 Create a Notice, and sends the activity to their followers
  2. on the follower side, the activity (and thus the Notice) is duplicated and stored locally. I'm not sure what ID is given to the copied activity though

Anyway, the point is that there are 2 distinct, separate copies of the same Notice. One on the actor who created it, and one on the follower. The 2 are separate, both have their own list of replies or "stars" etc. It's the responsibility of any 3rd actor to decide if they want to reply to the original Notice or the one that lives on the follower server. This is where I'm linking it with our issue about Ticket, and perhaps speaking in support of @jaywink's proposal. Basically, an actor can simply Create a Ticket and it will send the activity to the Tracker actor to notify it about the existence of a new Ticket. Then the Tracker keeps a local copy (like mentioned above for the case with Notice) and then it's the responsibility of any other actor to reply to the Tracker or the original actor who created the activity. Project maintainers will likely consider only the Issues that have been copied by their Tracker and ignore any development on any other actors.

Comments?

@fr33domlover Looking at "toots" on mastodon, they seem to work like this (unless I'm missing something): 1. user 1 Create a Notice, and sends the activity to their followers 2. on the follower side, the activity (and thus the Notice) is duplicated and stored locally. I'm not sure what ID is given to the copied activity though Anyway, the point is that there are 2 distinct, separate copies of the same Notice. One on the actor who created it, and one on the follower. The 2 are separate, both have their own list of replies or "stars" etc. It's the responsibility of any 3rd actor to decide if they want to reply to the original Notice or the one that lives on the follower server. This is where I'm linking it with our issue about Ticket, and perhaps speaking in support of @jaywink's proposal. Basically, an actor can simply Create a Ticket and it will send the activity to the Tracker actor to notify it about the existence of a new Ticket. Then the Tracker keeps a local copy (like mentioned above for the case with Notice) and then it's the responsibility of any other actor to reply to the Tracker or the original actor who created the activity. Project maintainers will likely consider only the Issues that have been copied by their Tracker and ignore any development on any other actors. Comments?
fr33domlover commented 1 month ago
Collaborator

@zPlus,

The toot is only cached on the remote follower side. It's just cached in the DB. It doesn't get its own ID URL (or at least, not a URL that is used in ActivityPub). Each toot has one ID URL: A URL on the instance of the toot's author. When you reply to a toot, you always reply against that URL. Cached copies are more like an optimization, they aren't a part of the protocol. They don't change behaviors and side effects.

If you write a specific client for a specific server and thus have access to the cache, you can use it, sure. But that's out of band, outside of ForgeFed. The canonical software-independent way to get the toot, or any other ActivityPub or ForgeFed object, is to HTTP GET the @id URL. In the case of toots, that means you get it from the server of the author.

This is more than about optimization, it's about authenticity. If you get my toot from a server that isn't mine, how can you be sure you get the real toot I wrote and not a fake version? Content signing is possible, but ActivityPub and the current Fediverse don't rely on that, and the way to get trustworthy content is to HTTP GET it from the server which you want to hold accountable for the content.

Jaywink's proposal relies on out-of-band caching, and doesn't solve the authenticity problem. In a comment on the forum post, I tried to add authenticity guarantees to it, but it seems quite more complicated than an in-band, actor model based solution. Just to clarify, centralized forges don't have an authenticity problem because there are no "other servers to trust", since there's just one server. That comfort is gone when you introduce federation.

My proposal is to have two in-band copies with separate ID URLs. Which is not how toots work. In my proposal, a ticket starts its life by being published on the author's server, but unlike a toot, the ticket's life continues on the repo's server. The author's copy would normally not be needed anymore, other than for history purposes. The canonical ticket and its replies and all other associated objects would be specified by the repo's server.

Comments? :)

@zPlus, The toot is only *cached* on the remote follower side. It's just cached in the DB. It doesn't get its own ID URL (or at least, not a URL that is used in ActivityPub). Each toot has one ID URL: A URL on the instance of the toot's author. When you reply to a toot, you always reply against that URL. Cached copies are more like an optimization, they aren't a part of the protocol. They don't change behaviors and side effects. If you write a specific client for a specific server and thus have access to the cache, you can use it, sure. **But that's out of band, outside of ForgeFed**. The canonical software-independent way to get the toot, or any other ActivityPub or ForgeFed object, is to *HTTP GET the @id URL*. In the case of toots, that means you get it from the server of the author. This is more than about optimization, it's about authenticity. If you get my toot from a server that isn't mine, how can you be sure you get the real toot I wrote and not a fake version? Content signing is possible, but ActivityPub and the current Fediverse don't rely on that, and the way to get trustworthy content is to HTTP GET it from the server which you want to hold accountable for the content. Jaywink's proposal relies on out-of-band caching, and doesn't solve the authenticity problem. In a comment on the forum post, I tried to add authenticity guarantees to it, but it seems quite more complicated than an in-band, actor model based solution. Just to clarify, centralized forges don't have an authenticity problem because there are no "other servers to trust", since there's just one server. That comfort is gone when you introduce federation. My proposal is to have two in-band copies with separate ID URLs. Which is *not* how toots work. In my proposal, a ticket starts its life by being published on the author's server, but unlike a toot, the ticket's life continues *on the repo's server*. The author's copy would normally not be needed anymore, other than for history purposes. The canonical ticket and its replies and all other associated objects would be specified by the repo's server. Comments? :)
zPlus commented 1 month ago
Owner

The author's copy would normally not be needed anymore, other than for history purposes

But then you still need signing to prove the authenticity of the sender (who created the message), right?

> The author's copy would normally not be needed anymore, other than for history purposes But then you still need signing to prove the authenticity of the sender (who created the message), right?
fr33domlover commented 1 month ago
Collaborator

You can prove author authenticity by linking to their message, where everyone can HTTP GET it and be sure it's authentic. A signature here would be an optimization, allowing to avoid the HTTP request, but that's an aspect the whole fediverse/ActivityPub shares, not specific to ForgeFed.

You can prove author authenticity by linking to their message, where everyone can HTTP GET it and be sure it's authentic. A signature here would be an optimization, allowing to avoid the HTTP request, but that's an aspect the whole fediverse/ActivityPub shares, not specific to ForgeFed.
Sign in to join this conversation.
Loading...
Cancel
Save
There is no content yet.