@lynnfoster I started to write the protocol specification: feps/fep-0837.md at main - feps - Codeberg.org. Would appreciate your feedback!
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.
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:
- You donāt want to support many primary Intents or many reciprocal Intents for one Proposal, correct? As in ākeep it simpleā.
- 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):
- 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 beunitBased: true
(you can receive however many hours of my service you need, so can others), the second would beunitBased: 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. - 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 includeavailableQuantity
so people know there is a limit. - 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 isimageList
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!
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 ofreciprocal
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.
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
Thank you! I will consider adding these to the spec.
Sorry, Iām not familiar with RDF.
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 addedavailableQuantity
- maybe later.image
- to be decided. I like the idea, but one of my goals is making proposals discoverable from social services like Mastodon, soattachment
might be a better choice.
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. 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?
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.
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 thenprovider
andreceived
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. BetweenReject(Create)
andReject(Offer)
, I would pick the latter. Or we can introduce some new activity (e.g.Request
orCommit
).
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 theProposal
.
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.
@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?
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.
I added example of
Agreement
to illustrate my thinking. Note theurl
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.
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!
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"
}
@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.)
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.
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.
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
I would like to withdraw FEP-d767, acknowledging that there was a lot of discussion on what became FEP-0837 in this thread. I think the use-case-based approach is much better that trying to make a complete Valueflows extension understandable or useful.
Iām not sure how to formally request that though. Can someone advise if I should do it differently for a proper record? Or feel free to consider this a formal request.
I submitted a pull request changing the FEP status from DRAFT to WITHDRAWN: #258 - Withdraw FEP-d767 - fediverse/fep - Codeberg.org