Closing a ticket

How to represent in ForgeFed the activity of closing a ticket? When you open a ticket, you use Create or Offer where the object is a Ticket. But how to change the ticket status, to mark is as resolved?

Currently, there’s the isResolved boolean property. Maybe we’ll also have a resolvedBy property specifying who resolved the ticket.

The most generic and standard way to update an object is the Update activity. The problem is, in S2S an Update contains the full object, not just the fields you changed! So it becomes impossible to reliably determine exactly what you changed. My opinion: Update should be used only for general updates where the best description that software can display to the user is “Alice updated object X” without any specific description of what changed. For specific changes, use specific activities that make it clear what the action is, what was meant to be changed.

PROPOSAL: Have a Resolve activity that resolves a Ticket. To reopen a ticket, use Undo, much like when unfollowing a user.

Thoughts? It’s very simple, so I think I’ll go ahead and implement this for now. Will change my code of course if we pick some different representation.

(Issue #98)

tl;dr skip to the last paragraph

After discussion on IRC and more thinking, we probably should decide between using Update for all objects edits, and using specific activities for specific changes.

Pros of using Update:

  • No need to add custom activities for the various changes, just use Update and the recipient figures out what changed
  • Perhaps less dev work, just implement a generic Update handler, it doesn’t even have to understand the type of the object being updated (but this is questionable because need to implement diffing for viewing and for determining exact changes when it matters for authorizing the change… see below)

Pros of using specific activities:

  • When observing an activity, it’s trivial to tell exactly what it changed; with Update it would be impossible to tell what the activity did
  • When observing the history of an object, telling what each Update did may be possible by diffing the Updates, but that works only if there’s no possibility for other activities to edit fields, otherwise the diffing would be confused. For example if some activity has a side effect that edits some field, the software observing the history would have to understand this activity and be able to simulate the side effect. Is there a good reason to be confident there’s a fixed set of activities that edit fields, and the edits can always be simulated?
  • Many activities make edits to objects (e.g. Follow edits a followers collection), and Update is only one of them. How do we decide what uses Update and what doesn’t? Suppose we decide that Update is for changes that don’t have any special side effects. Now merging an MR or applying a patch can’t use Update, because there’s a side effect. So whenever editing fields is a side effect of an activity that does something else, like applying a patch to a repo, any software viewing a history collection where it appears would have to understand it and be able to simulate the fields edits, otherwise the diffing of activities will get confused.

Clarification: We don’t need a custom activity for every single editable field, it just needs to be expressive enough for the kind of viewing forges offer, and the different distinguishable actions that have their own authorization rules. A simple rule: If an object history page displays some event in specific words (and not “user X updated object Y”) or there’s a dedicated button in UI to trigger this event, then we probably want to give is a dedicated activity type. There are just few of those per object type, so we it would be a small manageable number of custom activities to add. For example, a ticket’s data that isn’t in sub-objects is mostly just its textual content, perhaps who’s assigned to it, whether it’s resolved, the due date, maybe the tags if they aren’t in their own Collection… there are just few kinds of edits on these fields.

Obviously using Update means we don’t add custom vocabulary for kinds of changes, but I’m worried we’d end up making ourselves really struggle with that silly diffing of activities to determine what they did. The exact change is already known in advance, there’s specific intention to edit specific field(s), but instead of preserving that info, we’d be working with full objects and doing complicated processing to figure out that initial intention. There are fields related to each other, e.g. isResolved, resolvedBy and resolved all refer to the same event, of a ticket being resolved, so the software would be looking at them carefully, trying to figure out which of those 3 got changed and why and what it means and does resolvedBy match the actor of the Update, otherwise that’s quite confusing, etc. etc. :stuck_out_tongue:

Activity diffing may be required for determining authorization e.g. maybe some user is allowed to close/reopen a ticket, but not allowed to change its due date.

If we go for specific activities, it does mean we add custom activity types, but the implementation of those activities is extremely simple, no diffing is required, generating UI for viewing them would be trivial too. Forges already have pages and endpoints for specific actions like a “Close this ticket” button on a ticket page, right? They already handle changes in this way, and not via generic updates. So they’d simply have federation-supporting variants of those handlers, the “close this ticket” handler would support both a button click from a local user, and a remote e.g. Resolve activity coming from a remote user.

Can I please hear some good arguments in favor of using just Update for all the object changes? :stuck_out_tongue: otherwise, it seems so much simpler to add specific activities that do specific clear obvious edits, making authorization and display trivial to implement. We could still use Update, keeping it for the case where the display of “user X updated object Y” is enough, and perhaps specifying specific fields intended to be changed in that way (e.g. a ticket’s title and description). Then Update becomes trivial to handle too.

Note that most AP implementations use just S2S so they probably don’t care about viewing since they have their own custom C2S API for that, but C2S/viewing is in the spec, and they’re picking activities just for their own use while we’re writing a spec so we’re thinking bigger than covering the needs of one specific implementation.

Sorry for the late reply, I took some time to think about this. So, basically:

  • based on the AS spec, I don’t think Update is descriptive enough for us since it doesn’t define any way to describe what has changed. It’s basically a way to ping another actor to let them know that an object has changed, and that’s it. Theoretically you could detect what’s changed by comparing the Update activity with your local copy, but it doesn’t sound like a very robust option
  • we could introduce an activity called PartialUpdate or Edit that only sends the properties that have changed. My issue with this is that this feels like a “core” change that should happen on AS/AP rather than on forgefed
  • I’m OK with using a Resolve activity but I wonder how many more we’ll need to define. For example, what about changes to a ticket’s title or content? For these changes we could just use Update knowing that the information of what has changes (the title or the content) is lost, and the UI will simply show “the ticket has been edited X minutes ago”
  • w.r.t. Resolve, I would replace “isResolved” with a “status” property because a ticket (or a MR) can be in several states, for example FIXED, WONTFIX, CLOSED, OPEN. Unless maybe we can have both “isResolved” and “status”