FEP-d767: Extend ActivityPub with Valueflows

@lynnfoster I started to write the protocol specification: feps/fep-0837.md at main - feps - Codeberg.org. Would appreciate your feedback!

1 Like

I’ll do some detailed feedback in the next couple days.

Suddenly, this feels like a really good way to be doing this kind of extension in FEPs. Meaning, taking each use case at some coherent application-like or feature-like scope (marketplace seems like a really nice scope), and doing a separate FEP for each.

1 Like

I like this a lot! If any of the following doesn’t seem like something you want to spend time on, then no worries at all, feel free to skip over.

Questions for you:

  1. You don’t want to support many primary Intents or many reciprocal Intents for one Proposal, correct? As in “keep it simple”.
  2. Thinking of “offers” as something I want to provide to someone else as the primary Intent, and “requests” as something I want to receive from someone else as the primary Intent, you want to only support “offers”, right? As in a standard marketplace.

Question in general: Should this FEP be a general marketplace with the workflow you suggested? Or even more generalized, like for timebanks or other exchange use cases that would have Proposals with some follow through? And/or should some of the workflow you are proposing be separate FEPs, like maybe dispute resolution? There’s an in-process discussion here, with a marketplace example here.

Some possible suggestions to consider (but I’m not pushing anything):

  1. An example, maybe I have a bike shop, and I offer (Proposals) repairs for $25 per hour as a service. And I also have a used bike to sell. There is a property unitBased on Proposal, that would differentiate those. The first would be unitBased: true (you can receive however many hours of my service you need, so can others), the second would be unitBased: false meaning there’s only one to sell, then it’s gone. Or you could be selling 4 boxes of apples, and the buyer has to take all of them, it’s not always about being quantity 1.
  2. Or, you have 4 boxes of apples, which could be offered unitBased:true, with the unit being one apple, or the unit being one box. In this case you might want to include availableQuantity so people know there is a limit.
  3. Intent has an image property that is pretty useful when people are offering something that it really helps to see, like a used bike. Also there is imageList for carousel kind of things, but that might be overkill for the fediverse, don’t know.

Then there is an existing VF problem (not your problem) with many-to-many relationships, how to support that cleanly in RDF land, but also in relational/OO land, as we try to be technology agnostic as much as possible. Right now we are basically relational in the “system of record” model, even though it is expressed as a turtle file. So we have “extra” entities to resolve many-to-many relationships, in this case ProposedIntent. I probably fudged that in my examples to you, to not have to add a bunch of explanation. And I know we have to do something about it, possibly having parallel structures; possibly doing it RDF style, with notes on the UML model suggesting how to do in a relational database, don’t know yet, it all just adds complexity to VF - but cleans it up for the fediverse etc. So, I don’t want to muddy your very clean and clear example, so this isn’t to suggest changes, just putting it out there so you know it is an open issue for us. This also came up earlier when @pukkamustard did a simple implementation, and they did something like your example in their experiment.

A question, in case you (or others here) know: How would this be done in general in an RDF standard? Would Proposal reference a list of publishes Intents and a list of reciprocal Intents, and also would Intent reference a list of publishedIn Proposals? And would there be no relational “associative entity”? Thanks if any RDF person has an opinion!

1 Like

Interesting discussion!

A question, in case you (or others here) know: How would this be done in general in an RDF standard? Would Proposal reference a list of publishes Intents and a list of reciprocal Intents, …

A Proposal would probably be referencing a set of publishes rather than a list. However, a list is possible if there’s some semantic significance to the order of the publishes or reciprocal relationships.

… would Intent reference a list of publishedIn Proposals?

A publishedIn predicate is not necessary for finding all the Proposal entities referencing an Intent.

RDF relationships/predicates can be queried in either direction and, in general, they represent many-to-many associations (where “many” can be 1, of course).

Rather than explicitly defining a publishedIn predicate, it may be better to define an ontology where publishedIn is defined as an inverse relationship and can be inferred from the publishes predicate.

1 Like

Yes, this is intended to be minimal example of a federated marketplace where users can make offers to each other.

This is an interesting idea. One use case I’d like to support is a job marketplace, where “requests” would make more sense.

It should describe something simple, something that a developer could build as a hobby project. So it should be a single document, and I think there will be a short list of supported use cases.
Dispute resolution section will probably say that dispute resolution is out of scope of this document, but will provide some directions.

Also, I’m not actually building a marketplace. In my application there’s mechanism for supporting authors via recurrent donations, and I’d like to use Proposals to coordinate payments between servers.
But I hope this document will be useful for others too :slightly_smiling_face:

Thank you! I will consider adding these to the spec.

Sorry, I’m not familiar with RDF.

1 Like

I’ve updated the specification: feps/fep-0837.md at main - feps - Codeberg.org (diff). In particular, it now explains how one should respond to proposals.

Regarding your suggestions:

  • unitBased was added
  • availableQuantity - maybe later.
  • image - to be decided. I like the idea, but one of my goals is making proposals discoverable from social services like Mastodon, so attachment might be a better choice.
1 Like

image - to be decided. I like the idea, but one of my goals is making proposals discoverable from social services like Mastodon, so attachment might be a better choice.

Makes sense to use as much AP/AS as possible, as you have generally done.

Money is offered in exchange for a service.

I see this more as primarily a request for the service, not an offer for money, although I realize there is no Request activity type atm. Note also it should work the same way if there is money involved, or it is a gift. So that means basically people are communicating about the main intent. But I also see your thought process, so maybe I need to think more about it.

Proposals can be linked to actors (if actor provides a service) or to other objects (if they represent economic resources) using FEP-0ea0 payment links.

I’m not totally clear what this is trying to convey. In VF, every Intent (in this case) is linked to both an actor and to a resource specification (thing, service, money, etc.) So an actor providing a service is pretty much the same as an actor providing a thing, at the vocabulary level. But maybe you are thinking of something that I’m missing?

If payment link is used, its rel array MUST contain the string https://w3id.org/valueflows/Proposal

I understand this to be the destination (wallet, account, etc.) where you can send the payment later when you make it? In any case, it seems like it should link to the Intent to transfer the money, the Proposal is too broad. I’m also wondering how the Proposal looks with its payment link in the json-ld, is it separate or embedded in the Proposal object in some way?

Or maybe it is just linked to the Actor, and all payments get sent to the same place?

Responding to a proposal

I’m struggling with this a bit. I actually tend to think of the original Proposal as conceptually an offer in the context of a marketplace, represented by the primary Intent. And then the response might have to often include both how many the buyer wants of the primary Intent resource, and maybe how much they want to pay, if that is negotiable. So that’s 2 possible Commitments. If it’s not negotiable, then that can get calculated out by the seller, and the response only needs to be how many do they want of what was offered on the original proposal, which doesn’t seem like an offer.

In terms of the activity type Offer, it seems like one of those things that doesn’t fit in the list very well. But that’s maybe just me, and I don’t have experience with AP/AS beyond reading the specs a bunch of times. :slight_smile: Or maybe we add Request and try to get it into AS? But I still feel basically like Create, Update, Delete are the basic activities. Accept and Reject also seem useful. They all are more about the messaging mechanisms, not mixing in object-like content. Just an opinion.

If the response is a Commitment (or two), I wonder if the response should be a whole Agreement? Which can be accepted or rejected.

To me, it feels more like a Commitment if it is like an “order”, the assumption is you can have what you order, even if occasionally you can’t, and you’ll basically pay the asking price. But if you are negotiating price, it feels more like another Intent, and more like an offer. Hmmm.

In my application there’s mechanism for supporting authors via recurrent donations, and I’d like to use Proposals to coordinate payments between servers.

This is interesting. If I just read this, I don’t think Proposals. I just think about making donations directly, in VF an EconomicEvent. Or would the proposals be from the authors asking for recurring donations? Maybe reciprocal for some specific writing they are doing? Similar to a developer asking for donations for an app they are working on? Would an author ever reject a donation?

1 Like

What I meant is “request for a service” can be represented as a proposal where the primary intent is a money transfer and the reciprocal intent is a service. Is it not correct?

On a related note:

provider: the actor who provides the resource. This property is REQUIRED for primary intents.

I’m thinking about replacing this with attributedTo property on a proposal. This property is needed for transformation into “posts”, but then provider and received become redundant.

This is how proposal can be discovered by other actors. The link should not be attached to a proposal, it should be attached to some other object. For example:

{
  "id": "https://server.example/users/alice",
  "type": "Person",
  "inbox": "https://server.example/users/alice/inbox",
  "outbox": "https://server.example/users/alice/outbox",
  "attachment": [
    {
      "type": "Link",
      "name": "Bike repair",
      "href": "https://server.example/proposals/1",
      "rel": ["payment", "https://w3id.org/valueflows/Proposal"]
    }
  ]
}

The consuming implementation may discover the proposal by following the link. I’ll update specification with a better example.

I agree that Offer doesn’t fit here, but there must be a way to reject the Commitment during negotiation stage. Between Reject(Create) and Reject(Offer), I would pick the latter. Or we can introduce some new activity (e.g. Request or Commit).

Sometimes Agreement will contain additional fields such as payment details, so I think it should be published by the same party who published the Proposal.

Yes, something like that. Proposal is needed to initiate a payment that can be tracked by servers.

I don’t think so.

1 Like

We think of it that the money side would always be the reciprocal side, and that would follow through, not be based on the stage of the conversation. So primary always means “this is why we are doing this”. So even a “request for a service” exists because you want the service. The directionality is determined by the provider vs receiver.

One practical aspect of that way of thinking about it is that in a marketplace, if you are searching for what you are interested in, you shouldn’t have to see the reciprocal intents in your results. Or if there is matching logic between offers and requests, then reciprocal intents wouldn’t be part of that. I suspect our doc needs to be improved there.

Also noting that the reciprocal side won’t always be money, but in any case it will be “not the reason” that the proposal was made.

provider: the actor who provides the resource. This property is REQUIRED for primary intents.

I’m thinking about replacing this with attributedTo property on a proposal. This property is needed for transformation into “posts”, but then provider and received become redundant.

Unfortunately, I think both may be needed, I think of a couple reasons. attributedTo is who posted the message, right? In the case of groups, the user who posted might be different than the provider or receiver, which might be the group, say a bike repair collective. The other reason might be something we need to handle better in VF, which is that the only way we know if it is an offer (from me) vs a request (something I want) is provider vs receiver. We’ve thought about putting offer, request, and maybe other things in the future, as a code in Proposal, but haven’t done it.

I agree that Offer doesn’t fit here, but there must be a way to reject the Commitment during negotiation stage. Between Reject(Create) and Reject(Offer), I would pick the latter. Or we can introduce some new activity (e.g. Request or Commit).

I see your point. Not sure of the best way. Seems like this might be an ongoing kind of question on various AP extensions.

Sometimes Agreement will contain additional fields such as payment details, so I think it should be published by the same party who published the Proposal.

Yes, got it.

Yes, something like that. Proposal is needed to initiate a payment that can be tracked by servers.

Maybe this doesn’t matter, or maybe I still don’t understand the workflow, but wouldn’t it be that Agreement is what would initiate a payment? Like, maybe there will be several agreements that result from a proposal. Or, maybe it is at a higher level, like with the actor, who generally might accept a few methods of payment for any of their proposals? Don’t know.

1 Like

@lynnfoster I updated the specification (diff). Definitions of primary and reciprocal intents were corrected.

attributedTo is now required for proposals, and response to a proposal uses inReplyTo instead of satisfies.

I think using inReplyTo is generally a good idea. The marketplace could even maintain interoperability with microblogging platforms by accepting replies with type Note.

I added example of Agreement to illustrate my thinking. Note the url field that points to a payment page. This page should unique for each user who responds to a proposal. Agreement in that example is similar to an “order” on e-commerce websites.

Also, I noticed that clauses property is not present at Valueflows Ontology page. Is it intentional?

1 Like

This is because in VF the relationship points the other direction, a Commitment .clauseOf(Agreement). These terms show up here, although I see that this doc uses commitments rather than clauses, like Agreement.commitments(Commitment).

But I’m thinking from this experience that VF may need to accommodate inverses in the vocab itself, I’ve noticed schema.org does that. This is also semi-related to the publishes and reciprocal issue, which we’re still thinking about.

Anyhow, I’d suggest for now to use Agreement.commitments.

1 Like

:+1:

I added example of Agreement to illustrate my thinking. Note the url field that points to a payment page. This page should unique for each user who responds to a proposal. Agreement in that example is similar to an “order” on e-commerce websites.

:+1: Yes, that and the improved proposal payment example makes all of that much more clear for me now.

The whole thing is really starting to hang together!

1 Like

While reading ForgeFed specification I discovered a useful pattern: Accept activity with a result. In a federated marketplace this activity can be used instead of Create(Agreement):

{
  "type": "Accept",
  "actor": "https://market.example/users/alice",
  "object": "https://social.example/objects/fc4af0d2-c3a1-409b-947c-3c5be29f49b0/offer",
  "result": {
    "type": "Agreement",
    "id": "https://market.example/agreements/edc374aa-e580-4a58-9404-f3e8bf8556b2",
    ...
  },
  "to": "https://social.example/users/bob"
}
1 Like

@lynnfoster When the someone is delivering a service, but it’s something intangible and uncountable, should resourceQuantity be omitted? Or should we just say that it is “one item”? E.g. {"hasUnit": "one", "hasNumericalValue": "1"}?

Usually that would be 1 service, like 1 taxi cab ride or one haircut. So yes {"hasUnit": "one", "hasNumericalValue": "1"}. Or if there are bundled services, maybe one process will deliver 1 train transportation from X to Y, plus also delivering transportation of 2 extra suitcases with the person (which are counted because there is an extra charge per suitcase). That would be 2 commitments on the same agreement, one for the person and one for the suitcases.

I think it is best to include the resourceQuantity in any case, even if it is just ‘1’. It might be counted at some level, like the barber delivered 145 haircuts last month. Or the train transported 200 people and 256 suitcases on this trip.

Do you have a different kind of example you are thinking of that is “intangible and uncountable”? I’d be interested.

Note the “one” can be eliminated on the UI, because it usually doesn’t make any sense to people. I did file a PR with the OM2 standard about that, we’ll see what happens, More alternative labels for `one`? · Issue #77 · HajoRijgersberg/OM · GitHub, still discussing. The author also suggested taking off the label on the UI, which we have done, but that’s just extra code in a lot of apps. (That is not just about services particularly, just seems possibly related to this question.)

1 Like

I was thinking about requests like “please help me do X” (without reciprocal intent).
From implementer’s perspective, it is better when resourceQuantity is always present (makes the code simpler), so I’ll keep it as REQUIRED in FEP-0837.


There’s a new fediverse project called Flohmarkt: https://codeberg.org/grindhold/flohmarkt.

It is not using Valueflows, but I contacted the developer and they might consider implementing some parts of FEP-0837. Currently they use Note type to represent offers, because such objects are accepted by most ActivityPub servers including Mastodon. I changed the specification accordingly: allowed proposals to have the Note type.

1 Like

Cool! Thanks for connecting with them re. VF. And it makes sense to allow the Note type. Then maybe people who want to post offers and requests also into AP servers that don’t support VF could add enough into the content that it says textually what they need to say about any of the VF data that would be ignored.

1 Like

I finished writing the Federated Marketplace specification and submitted it to the main FEP repo: #146 - FEP-0837: Federated Marketplace - fep - Codeberg.org

Diff between this version and the previous one: FEP-0837: Update proposal · 0adcbfb04c - feps - Codeberg.org

1 Like