FEP-d767: Extend ActivityPub with Valueflows

Hello!

This is a discussion thread for the proposed FEP-d767: Extend ActivityPub with Valueflows. Please use this thread to discuss the proposed FEP and any potential problems or improvements that can be addressed.

Summary

A standard method to extend ActivityPub/ActivityStream with Valueflows vocabulary, to enable varied economic networking activity in the fediverse.

2 Likes

@lynnfoster, the following is just a technical comment.

First, in order for activities to be distributed in ActivityPub, they should have recipients, i.e. to, cc, bto, bcc, audience. It would be good if your examples could include them.

In a similar note, it would be advantageous for all objects that can be considered “owned by someone” to have this owner as an attributedTo property. So taking your first example, it would result in something akin to:

{
  "@context": [...],
  "type": "Create",
  "actor": {
    "type": "Person",
    "name": "Sally"
  },
  "to": {
      "type": "Group",
      "name": "SocialHub"
  },
  "object": {
    "attributedTo": {
       "type": "Person",
      "name": "Sally"
     },
    "type": "vf:Plan",
    "content": "Collaborate on defining the VF extension to AP/AS. Propose as a FEP (Fediverse Enhancement Proposal).",
    "name": "Define AP-VF Extension"
  },
  "summary": "Sally created a project plan."
}

Second, in order for the first object to be valid json-ld, it should have the form:

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    {
      "vf": "https://w3id.org/valueflows/"
    }
  ],
  "type": "Create",
  "actor": {
    "type": "Person",
    "name": "Sally"
  },
  "object": {
    "type": "vf:Plan",
    "content": "Collaborate on defining the VF extension to AP/AS. Propose as a FEP (Fediverse Enhancement Proposal).",
    "name": "Define AP-VF Extension"
  },
  "summary": "Sally created a project plan."
}

I changed the @context to be a list of a string, and an object.

Third, relating to

"vf:name": "HUMANs", # could use target for this?

HUMANs is probably the meaning assigned to as:Public, i.e. the usually used public collection. I’m of course wondering now, if you mean by humans as in “public without bots”?

I hope this helps.

1 Like

One question we have about how to best extend AP with something like Valueflows (VF). More to come later. This has to do with what is best as an Activity vs. an Object.

In the VF model, there are things that are like activities, in relation to objects, in that they are “edges” on the directed graph created in VF, the “resource flows” between agents. One way to look at them is that they are “proposals” (offers, requests), “commitments” (promises to do something like some work, or transfer something for exchange), “economic events” (record you did something or transferred something. Another way to look at them, which sound more like activities, is they all have an “action” to let VF know what to do with the resources. Examples are “produce”, “deliver service”, “consume”, “use”, “work”, “pick up”, “drop off”, “transfer”, “move”. But those are used at all three of the stages above. There are also other things that can be thought of as verbs, like “plan”, which includes a Plan, some Processes, some Commitments. Or “commit”, when someone promises to do or provide something.

When @mayel from Bonfire and I discussed this, actually some years ago, we came to the conclusion that we should just make VF concepts all into AS Objects, and use activities Create, Update, Delete. And maybe a few more like Accept, Reject, tbd. This keeps AP/AS and VF the least entangled, as things move forward with new versions, in the various documentation, etc. Or as different extensions want the same activity. And it keeps things conceptually simpler. But we did have some advice from an experienced fediverse dev that we should try to create appropriate new activities. As of now the 2 or 3 projects that have implemented VF as an extension do it the first way, everything is an object, using Bonfire as the example. And I like it, in that it uses AP/AS for the messaging capability, and keeps the content separate. But now the activities are kind of a mixed thing.

It seems like there might be already, or should be in the future, some cross-fediverse consensus about how to extend AP/AS in general, as relates to this question. So, all advice is welcome. Or if I haven’t looked at appropriate examples where there are similar extensions, links would be really helpful.

1 Like

Another question we have is about complex Objects. Is there any problem with that? The software that receives the data would of course need to know how to handle them, as well as when they come one at a time, which they also might.

One example is a Plan might have many connected Processes, each of which has input and output Commitments or Intents (nobody has committed yet). Each Process and each Commitment will reference various existing data also.

TL;DR: I have a strong preference for using Create, Update, and Delete as much as possible.

Just using these makes interoperability with my project bovine “easy”. By this, I mean that objects should behave under these operations as one expects. In order to demonstrate this (aka brag), I put together a test case for it. It demonstrates that

  • Create a Valueflows Object
  • Delete a Valueflows Object

works as one would expect. Side note: I needed to add ids to the objects for everything to work nicely.


As far as other interactions with objects are concerned, e.g. Like, I believe that one can probably abstract these with an interactions collection that includes all Activities whose object has a certain id. This would allow one to add custom Interactions, e.g. EmojiReaction.

If one builds this correctly, it would also include Activities from something like Valueflows.

1 Like

A standard method to extend ActivityPub/ActivityStream with Valueflows vocabulary, to enable varied economic networking activity in the fediverse.

@lynnfoster In the context of this FEP, what is an economic activity? Can this vocabulary be used to describe a simple exchange, like sending an invoice (seller → buyer) and notifying about a payment (buyer → seller)?

Yes, except the model is more abstracted and simplified than that. It’s based on an ontology developed in academia called REA (Resources-Events-Agents). So a simple exchange is 2 reciprocal economic events, where a resource goes from agent A to agent B, and another resource goes from agent B to agent A. So the same structure will support a traditional sale, or barter, or mutual credit, all of which are just simple exchanges. Before the actual events, there might be an agreement with 2 corresponding commitments (promises), which you’d need to create an invoice after say one of the commitments is fulfilled. But the invoice is thought of more like an artifact or a report, i.e there’s no “invoice” object.

The other big piece of “economic activity” is coordinating production and distribution.

1 Like

In the specific case I’m thinking about, a purchase of a good (or a service) can be represented with 3 activities. If we use the terms from ActivityStreams vocabulary, the process may look like this:

  • Buyer sends Offer to a seller, where the object property denotes an action (e.g. Buy) and target property points a product.
  • Seller sends TentativeAccept to a buyer, where object property points to Offer activity and target property points to an invoice.
  • Once payment is completed (via a side channel), seller sends Accept to a buyer, with the same properties as the previous activity.

It is possible to represent the same sequence using the Valueflows terms without increasing the number of activities and overall complexity?

The idea of a federated marketplace comes up from time to time in discussions, so I think it would be good to present a solution to this problem in “Examples” section of this FEP.

First point on this:

https://w3id.org/valueflows#AccountableEffect

Does not give back linked data, and it should

rapper -g https://w3id.org/valueflows#AccountableEffect
rapper: Parsing URI https://w3id.org/valueflows#AccountableEffect with parser guess
rapper: Serializing with serializer ntriples
rapper: Error -  - XML parser error: Entity 'middot' not defined

I will grant you that AS2/AP itself was released in a state that was not a very high standard of Linked Data, itself. But, that can perhaps be cleaned up. And new FEPs should really have a certain bar of quality. Namely if you dereference the vocab term, for any of the mime types that are available (preferably only one!) it should give back, valid Linked Data.

It is possible to represent the same sequence using the Valueflows terms without increasing the number of activities and overall complexity?

@silverpill sorry for the delay. Here’s one possibility, although I’m having trouble understanding exactly how the marketplace would work in ActivityPub thinking. And how a pattern of more tightened up messaging between actors should work for economic activity, vs social activity. Might open a more general issue for that after my partner @bhaugen thinks more about it, he has the distributed transaction background and I don’t.

I have more messages, but I think that is not added complexity, just more for completeness of the use case.

First the Seller posts the product offered in the marketplace. (Happened before your sequence.) This potentially could be an as:Offer, not an as:Create.

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    {
      "vf": "https://w3id.org/valueflows/",
      "om2": "http://www.ontology-of-units-of-measure.org/resource/om-2/"
    }
  ],
  "summary": "Alice posts an offer of a bike in the Fedi Market.",
  "type": "Create",
  "actor": {
    "id": "https://social.example/alice",
    "type": "Person",
    "name": "Alice"
  },
  "to": {
    "id": "https://fedi.example/market",
    "type": "Group",
    "name": "Fedi Market"
  },
  "object": {
    "type": "vf:Proposal",
    "id": "https://alice.example/proposal/1",
    "vf:name": "Offering used bike",
    "vf:publishes": {
      "type": "vf:Intent",
      "id": "https://alice.example/intent/11",
      "vf:action": "transfer"
      "vf:resourceInventoriedAs": "https://alice.example/resource/bike1"
      "content": "Blue one-speed bike, 15 years old, some rust.",
      "vf:provider": "https://social.example/alice",
    },
    "vf:reciprocal": {
      "type": "vf:Intent",
      "id": "https://alice.example/intent/12",
      "vf:action": "transfer"
      "vf:resourceConformsTo": "https://www.wikidata.org/wiki/Q4917", # US Dollar
      "vf:resourceQuantity": {
        "type": "om2:Measure",
        "om2:hasNumericalValue": "30",
        "om2:hasUnit": "each"
      },
      "vf:receiver": "https://social.example/alice",
    },
  }
}

The Buyer sees the offer, and responds. This corresponds to your first bullet, except that I am thinking of this more like an order, which maybe is like an offer to buy, or seems more definite? I’m imagining some level of marketplace fediverse instance. But there are certainly other ways to imagine it.

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    {
      "vf": "https://w3id.org/valueflows/",
      "om2": "http://www.ontology-of-units-of-measure.org/resource/om-2/"
    }
  ],
  "summary": "Bob orders bike from Alice.",
  "type": "Create",
  "actor": {
    "id": "https://pub.example/bob",
    "type": "Person",
    "name": "Bob"
  },
  "to": {
    "id": "https://social.example/alice",
    "type": "Person",
    "name": "Alice"
  },
  "cc": {
    "id": "https://fedi.example/market",
    "type": "Group",
    "name": "Fedi Market"
  },
  "object": {
    "type": "vf:Agreement",
    "id": "https://fedi.example/agreement/1",
    "vf:clauses": [ {
        "type": "vf:Commitment",
        "id": "https://fedi.example/commitment/5",
        "vf:satisfies": "https://alice.example/intent/11",
        "vf:action": "transfer",
        "vf:resourceInventoriedAs": "https://alice.example/resource/bike9",
        "vf:provider": "https://social.example/alice",
        "vf:receiver": "https://pub.example/bob"
      },
      {
        "type": "vf:Commitment",
        "id": "https://fedi.example/commitment/6",
        "vf:satisfies": "https://alice.example/intent/12",
        "vf:action": "transfer",
        "vf:resourceConformsTo": "https://www.wikidata.org/wiki/Q4917", # US Dollar
        "vf:resourceQuantity": {
            "type": "om2:Measure",
            "om2:hasNumericalValue": "30",
            "om2:hasUnit": "each"
        },
        "vf:provider": "https://pub.example/bob",
        "vf:receiver": "https://social.example/alice"
      },
    ]
  }
}

Then there is something like your bullet point 2, because the order needs confirmation from the Seller. Unless this isn’t really needed unless there is a problem and the order can’t be fulfilled? If so, that would save a step.

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    {
      "vf": "https://w3id.org/valueflows/",
      "om2": "http://www.ontology-of-units-of-measure.org/resource/om-2/"
    }
  ],
  "summary": "Alice confirms order for bike to Bob.",
  "type": "Accept",
  "actor": {
    "id": "https://social.example/alice",
    "type": "Person",
    "name": "Alice"
  },
  "to": {
    "id": "https://pub.example/bob",
    "type": "Person",
    "name": "Bob"
  },
  "cc": {
    "id": "https://fedi.example/market",
    "type": "Group",
    "name": "Fedi Market"
  },
  "object": {
    "type": "vf:Agreement",
    "id": "https://fedi.example/agreement/1"
  }
}

Then the exchange actually happens. I’ve recorded both sides of this, the order would depend on how the marketplace operates. Seems like most e-commerce wants payment first, but also seems like that could depend on the level of trust within the group. The payment is your bullet 3, the bike transfer is just for completeness. I don’t know if we would need some kind of accept or countersign kind of thing so that both parties on each transfer explicitly say it happened? For now, I’m assuming not, and that since the receiver is recording the economic events, that is good enough. Or, the provider could be recording the events, and if something doesn’t arrive, that is an exception that gets handled.

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    {
      "vf": "https://w3id.org/valueflows/",
      "om2": "http://www.ontology-of-units-of-measure.org/resource/om-2/"
    }
  ],
  "summary": "Alice receives US Dollars from Bob.",
  "type": "Create",
  "actor": {
    "id": "https://social.example/alice",
    "type": "Person",
    "name": "Alice"
  },
  "to": {
    "id": "https://pub.example/bob",
    "type": "Person",
    "name": "Bob"
  },
  "cc": {
    "id": "https://fedi.example/market",
    "type": "Group",
    "name": "Fedi Market"
  },
  "object": {
    "type": "vf:EconomicEvent",
    "id": "https://fedi.example/event/1",
    "vf:fulfills": "https://fedi.example/commitment/6",
    "vf:action": "transfer",
    "vf:resourceConformsTo": "https://www.wikidata.org/wiki/Q4917", # US Dollar
    "vf:resourceQuantity": {
      "type": "om2:Measure",
      "om2:hasNumericalValue": "30",
      "om2:hasUnit": "each"
    },
    "vf:provider": "https://pub.example/bob",
    "vf:receiver": "https://social.example/alice",
  }
}
{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    {
      "vf": "https://w3id.org/valueflows/",
      "om2": "http://www.ontology-of-units-of-measure.org/resource/om-2/"
    }
  ],
  "summary": "Bob receives bike from Alice.",
  "type": "Create",
  "actor": {
    "id": "https://pub.example/bob",
    "type": "Person",
    "name": "Bob"
  },
  "to": {
    "id": "https://fedi.example/market",
    "type": "Group",
    "name": "Fedi Market"
  },
  "cc": {
    "id": "https://social.example/alice",
    "type": "Person",
    "name": "Alice"
  },
  "object": {
    "type": "vf:EconomicEvent",
    "id": "https://fedi.example/event/2",
    "vf:fulfills": "https://fedi.example/commitment/5",
    "vf:action": "transfer",
    "vf:resourceInventoriedAs": "https://alice.example/resource/bike9",
    "vf:resourceQuantity": {
      "type": "om2:Measure",
      "om2:hasNumericalValue": "1",
      "om2:hasUnit": "each"
    },
    "vf:provider": "https://social.example/alice",
    "vf:receiver": "https://pub.example/bob"
  }
}
1 Like

@helge Thanks all for the feedback!

First, in order for activities to be distributed in ActivityPub, they should have recipients, i.e. to, cc, bto, bcc, audience.

Thanks! Trying to do that now here, will update the actual FEP examples eventually. And also correcting the @context.

In a similar note, it would be advantageous for all objects that can be considered “owned by someone” to have this owner as an attributedTo property.

Not sure I understand this yet, still thinking about ownership of these kinds of objects. Many of them involve collaborations. But I’ll take a deeper look.

“vf:name”: “HUMANs”, # could use target for this?

HUMANs is probably the meaning assigned to as:Public, i.e. the usually used public collection.

Sorry that was confusing. No, HUMANs is a mutual aid network we work with. I’ll change it in the example to something else.

And, thanks for your test, very cool! As a thank-you, I took a picture for you of one of the bovines that live next door to us. :wink:
bovines

Does not give back linked data, and it should

@melvincarvalho thanks for trying this! We do know that and have an open issue, which clearly needs to get prioritized.

The placement of a product (bike) and its delivery are omitted in my example, so it looks like our activity sequences are equivalent and have the same number of messages. I think that answers my questions, thanks!

I have a related question: Do you plan on using the followers mechanic with Valueflows? Or will it be based on specified recipients?

Good question. Tentative thoughts:

I think we would want to use the followers collection as it is used in AP. So random people could follow something in VF, meaning they are observing and get copies of posts, but aren’t participating as a member of a group or process (doing work together) or exchange or whatever.

And then we’ll want something specific (and new I think) for people participating in something. Maybe new types of collections? Or maybe just some logic in apps (frontend? backend?) that knows rules, like everyone participating in a process gets a copy of posts of activity to that process, etc.

A topic for some study, and some discussion with Bonfire when they have headspace, they may have some of this in code. @mayel @ivan

1 Like