5e-bits/5e-database

`Choice` structure reform

fergcb opened this issue Β· 106 comments

Summary

There are a number of issues with the Choice structure that keep cropping up: nested Choices, arrays of mixed types, no way to easily describe or deserialize the structure... This issue aggregates those problems and proposes a reformed Choice structure that aims to solve them.

The details of the existing problems and proposed solutions are explained below. I've also described the final proposed structure in TypeScript syntax for reference (this is not intended to be official documentation), and provided an example of the structure in the form of the Fighter's starting_equipment_options array. Both can be found in this gist: https://gist.github.com/fergcb/a02760c460def3904358cbdfea9312c6

With the community's approval I'll be more than happy to take up the task of implementing the proposal, as well as producing the user-facing documentation.

Details

Consistency

The biggest issue being addressed is consistency. A lot of data consumers don't like arrays with items of mixed types (#274), and there are a variety of structures that can appear in different places without any straightforward way of identifying them.

The proposal uses an inheritance pattern to give all items in an array a common type, for easy deserialization. For example, in the from array of a Choice, there could be nested choices, arrays of items that must each be resolved separately, or a "terminal", single item. Currently these are given in their raw forms; the from array could contain Choice objects, JSON arrays, or single objects.

To solve this, every item in the array will now be an object with an option_type attribute of either choice, multiple or single, which indicates the structure of the underlying data. The same pattern is used to identify whether the Choice is between an array, as described above, or a ResourceList. See the JSON snippet in the gist for examples.

Descriptions

Another issue with the current Choice structure is that it can be hard to explain to a human user what they're actually choosing between (#355). While it is easy to list the options available, and the type attribute of a choice provides some information, a consumer has no way of indicating where the choices are coming from, or what they are. For example type may indicate that a "proficiency" is being chosen, so an application could easily render something like "Choose one proficiency:", but the underlying choice in the SRD is actually "one type of artisan's tools or one musical instrument"

To solve this, the proposal adds an optional desc string for Choices, so that consumers don't have to write any funky algorithms to tell a human user what they're choosing from. The string should include the text from the SRD that describes what needs to be chosen, e.g. "a wooden shield or any simple weapon", "one type of artisan's tools or one musical instrument", "a martial weapon and a shield or two martial weapons", etc.

Amendments

  • The type attributes of Option and OptionSet objects have been renamed to option_type and option_set_type respectively, to more easily distinguish the difference between the structures from the programmer's perspective.
  • The array value of the option_type attribute has been changed to multiple, to help indicate that all of the items in the JSON array come with that option.
  • The resource_list value of the option_set_type has been changed to resource_list_url to better indicate the structure of the data: it is a string holding a URL that resolves to a ResourceList, not an actual ResourceList in its own right.
  • The resource_list OptionSet now holds the ResourceList's URL under resource_list_url, rather than just url.
  • The EquipmentCategoryOptionSet type has been added to support equipment categories properly (which have a structure distinct from ResourceLists). EquipmentCategories are now linked with an APIReference.
  • The single Option type has been split into reference and action. The reference type is identical to the previous single type, corresponding to a counted APIReference. The action type is intended for use within "Multiattack" actions, referring to actions, by name, within the same Monster document. An example based on the "Captain" has been added to the Gist.
  • The array option_set_type has been renamed to options_array, to make it clear what the array contains.

Final Spec

This section describes the state of the proposal after the discussed amendments, to aid with the implementation:

Choice

The Choice structure describes a decision that must be made by a player during character creation or gameplay. It has four attributes:

  • desc (string, optional): A description of the choice to be made in human-friendly and (where possible) SRD text.
  • choose (number): The number of options that must be chosen. The same option can be chosen more than once.
  • type (string): A string indicating the type of object that will be chosen.
  • from (object): An object containing the options to choose from. This may take one of a number of forms as described below.

OptionSet

The OptionSet structure provides the options to be chosen from, or sufficient data to fetch and interpret the options. All OptionSets have an option_set_type attribute that indicates the structure of the object that contains the options. The possible values are options_array, equipment_category and reference_list. Other attributes on the OptionSet depend on the value of this attribute.

  • options_array
    • options (array): An array of Option objects. Each item in the array represents an option that can be chosen.
  • equipment_category
    • equipment_category (APIReference): A reference to an EquipmentCategory. Each item in the EquipmentCategory's equipment array represents one option that can be chosen.
  • resource_list
    • resource_list_url (string): A reference (by URL) to a collection in the database. The URL may include query parameters. Each item in the resulting ResourceList's results array represents one option that can be chosen.

Option

When the options are given in an options_array, each item in the array inherits from the Option structure. All Options have an option_type attribute that indicates the structure of the option. The possible values are reference, action, multiple and choice. The value of this attribute indicates how the option should be handled, and each type has different attributes.

  • reference - A terminal option. Contains a reference to a Document that can be added to the list of options chosen.
    • item (APIReference): A reference to the chosen item.
  • action - A terminal option. Contains information describing an action, for use within Multiattack actions.
    • action_name (string): The name of the action, according to its name attribute.
    • count (number): The number of times this action can be repeated if this option is chosen.
    • type (string = "melee" | "ranged", optional): For attack actions that can be either melee or ranged (e.g. for thrown weapons).
  • multiple - When this option is chosen, all of its child options are chosen, and must be resolved the same way as a normal option.
    • items (array): An array of Option objects. All of them must be taken if the option is chosen.
  • choice - A nested choice. If this option is chosen, the Choice structure contained within must be resolved like a normal Choice structure, and the results are the chosen options.
    • choice (Choice): The Choice to resolve.

I already said this on discord but am saying it again for github users..

I approve of the structure. My main concern is how we would document this. I am sure it can be done properly it's just something we will have to be careful with.

Additionally I think it would be best to have more specific type names in the data. The type field for OptionSets could be named option_set_type and the type field for Option could be named option_type. I think the actual values for these fields are named sufficiently.

Good luck.

Additionally now that I'm thinking about it, it could also be good to use a regular APIReference as an Option as well. It seems odd to have certain things (like spells, sub-features and sub-traits) to be counted, even if it's just 1. Perhaps this isn't needed though.

Additionally I think it would be best to have more specific type names in the data. The type field for OptionSets could be named option_set_type and the type field for Option could be named option_type. I think the actual values for these fields are named sufficiently.

I can see this being beneficial. If others agree I'd be happy to go with this.

now that I'm thinking about it, it could also be good to use a regular APIReference as an Option as well. It seems odd to have certain things (like spells, sub-features and sub-traits) to be counted, even if it's just 1. Perhaps this isn't needed though.

I had thought about this, and cut it out in an effort to simplify a little, with the justification that a count of 1 does the trick, but that is quite StartingEquipment-centric thinking from me. There are other places that do require counts, like actions (esp. Multiattack actions), but those that don't probably outweigh them.

Requiring count across the board works, but might not be as intuitive. Introducing an uncounted APIReference would also work, might be more intuitive, but would increase complexity. I'm interested to know what others have to say about this.

Globally, I like this structure, especially the desc suggestion, but I believe names should be better.

Option

type Option = {
  type: 'single' | 'array' | 'choice'
  prerequisites?: Prerequisite[]
} & (SingleOption | ArrayOption | ChoiceOption)

I don't like the word array: it's too JSON-y and not data enough. In regards to data, I believe the term list is preferred. When it comes to a choice between choice, array and single, it's very weird to use array here. Can we use choice, multiple, single, or maybe one_of, all_of, one? I'm not a native English speaker but to my ear as a developer for so many years, this sounds very strange. So maybe other words can be preferred. Any suggestion?

OptionSet

type OptionSet = {
  type: 'resource_list' | 'array'
} & (ResourceListOptionSet | ArrayOptionSet)

This really requires improvement:

  • the resource_list is not a list of resource: it's a reference to a resource list. Can we just use reference instead of resource_list? This way it's clear that we must go to some other place to lookup the data. Currently, as a reader of the JSON, I'd nearly expect that it's filled with the actual value. I really mean reader of the JSON, not a reader of the .ts: the .ts should be there to explain the JSON, not to enforce it.
  • Also the array here makes little sense as seen here. I suggest we use the name options instead of array.

Ok, I understand that some people will invalidate my first point with my second or vice-versa, but the point here is to be self-contained relevancy. And OptionSet can actually contain a reference to options, or options themselves. Hence my suggestion.

Yes, I know, naming is hard. Sorry...

I don't like the word array: it's too JSON-y

The whole point of the attribute is to describe the structure of the underlying data. That data is a JSON array; hence, the use of JSON terminology.

Certainly choice, multiple, single is far better than one_of, all_of, one, as it much closer to describing the actual structures here. For example, one_of implies an array of options, one of which must be selected, when in actual fact, it corresponds to a Choice object. Once again, I am interested to hear what others have to say on this.

the resource_list is not a list of resource: it's a reference to a resource list. Can we just use reference instead of resource_list?

I would be happy to use resource_list_reference, or similar. As you're correct, it's not a ResourceList, but a reference to one. I feel reference alone is too vague.

the .ts should be there to explain the JSON, not to enforce it.

The entire purpose of TS types is to enforce the type, or structure, of data at compile time. While it may help explain the structure for those who understand the syntax, it is chiefly here to allow the schema to be enforced while it is being implemented.

the array here makes little sense as seen here. I suggest we use the name options instead of array.

The solution to this is not to give the attribute a value of options. That does not describe the structure of the data. The from attribute of the Choice structure contains the options. The type attribute of the OptionSet structure indicates the format in which those options are presented: Either a ResourceList, or a JSON Array.

I believe Wyzards' suggestion of naming the attributes option_set_type and option_type is a far stronger suggestion, as it actually corresponds to the purpose of the attributes, rather than trying to give them a different, less useful purpose altogether.

ETA: as I have mentioned in previous discussions, the value of the type attribute IS NOT a name. Treating it as one is counter-productive.

The whole point of the attribute is to describe the structure of the underlying data. That data is a JSON array; hence, the use of JSON terminology.

No, we can't just go around and name everything array. If I have a list of bikes in a structure and I name that list of bikes list, my reviewer will reject my code telling me to call it bikes or similar. An array is a good structure, but array is a bad name for something that uses that structure. I don't really care if it's the one_of and friends that's selected or multiple, but array has to leave, here.

The entire purpose of TS types is to enforce the type, or structure, of data at compile time. While it may help explain the structure for those who understand the syntax, it is chiefly here to allow the schema to be enforced while it is being implemented.

I understand why TS is here, but I don't work in JavaScript and friends. I work in different languages such as Java and Python, and if at some point in time, TypeScript goes against JSON and creates its own TSON (for instance), your stance means that you'll think about follow it, making the data secondary to the structure rather than primary as it (still) currently is. I must say that if the data is not in pure JSON, I'm out, forking the data of this project.

So yes, it's important to understand that JSON is king, and TS is only here to support it.

The solution to this is not to give the attribute a value of options. That does not describe the structure of the data.

It's not about describing the structure of the data: it's about describing the data. array is a bad name and I'll reject it. I'm fine with you not liking options, but let's find something else that is not options or array in that case. We can try going with option_set_type and option_type, as you mention: I'm fine with testing it at the very least.

It's not about describing the structure of the data: it's about describing the data.

This is were we disagree. As I keep saying, the type attribute only describes the structure of the data. That's it.

Please stop getting hung up on the TS thing. It will not be included in the project anywhere. It is only used by me to validate the data as it is being entered. I only included it for people who do understand it, in the hope it may assist the explanation. You don't even have to lay eyes on it if you don't want to.

I feel like almost all of your comments stem from a fundamental misunderstanding of the issues and the proposed solutions, and I don't know how I can explain them in ways other than those I already have. I'm going to reserve further comment until others have had a chance to take a look at the proposal and the discussion, in the hope that different perspectives can shed some light on this blip in communication.

I do understand your proposals. Structurally your suggestion is excellent. I really like it. Please just try to read the JSON you wrote (lines 61-72):

  {
    "desc": "(a) a martial weapon and a shield or (b) two martial weapons",
    "type": "equipment",
    "choose": 1,
    "from": {
      "type": "array",
      "options": [
        {
          "type": "array",
          "items": [
            {
              "type": "choice",

What I read is: "my type is array, but I'm offering options as field".

Then the very next object reads "my type is array, but I'm offering items as field".

So because you prefer to describe the structure of the data and not the data itself, there is a huge confusion here: at some point an object that says it's an array contains options and at some other time, another object that says it's an array contains items. How is that not confusing? This is what I have an issue with.

All the rest is fine by me, and I mean all.

I don't like the word array: it's too JSON-y

The whole point of the attribute is to describe the structure of the underlying data. That data is a JSON array; hence, the use of JSON terminology.

Certainly choice, multiple, single is far better than one_of, all_of, one, as it much closer to describing the actual structures here. For example, one_of implies an array of options, one of which must be selected, when in actual fact, it corresponds to a Choice object. Once again, I am interested to hear what others have to say on this.

the resource_list is not a list of resource: it's a reference to a resource list. Can we just use reference instead of resource_list?

I would be happy to use resource_list_reference, or similar. As you're correct, it's not a ResourceList, but a reference to one. I feel reference alone is too vague.

the .ts should be there to explain the JSON, not to enforce it.

The entire purpose of TS types is to enforce the type, or structure, of data at compile time. While it may help explain the structure for those who understand the syntax, it is chiefly here to allow the schema to be enforced while it is being implemented.

the array here makes little sense as seen here. I suggest we use the name options instead of array.

The solution to this is not to give the attribute a value of options. That does not describe the structure of the data. The from attribute of the Choice structure contains the options. The type attribute of the OptionSet structure indicates the format in which those options are presented: Either a ResourceList, or a JSON Array.

I believe Wyzards' suggestion of naming the attributes option_set_type and option_type is a far stronger suggestion, as it actually corresponds to the purpose of the attributes, rather than trying to give them a different, less useful purpose altogether.

ETA: as I have mentioned in previous discussions, the value of the type attribute IS NOT a name. Treating it as one is counter-productive.

I think the choice, multiple, single name scheme is best. Also how about resource_list_url for the resource list url lol... I agree that reference would be too ambiguous.

Also I agree with what ferg is saying about the array naming. The type field is describing the literal type structure of the choice, so array and resource list seems most fitting since it's not actually describing the content of the optionset itself. The type field exists here to distinguish from the two OptionSets type and tells the consumer how to handle them. It isn't indicating what type of data is stored within the choice. When it comes down to it I'm not too hung up on whether array is renamed to options or not, I think either is properly indicative of what is stored within it.

If the type field were meant to describe the type of CONTENTS, then I would agree with @ogregoire but as far as I can tell that is not the case.

Was just taking a look again at the gist and noticed that your schema for Option has an attribute called prerequisites. It's clear to me what the purpose of this could be, but could you provide an example that makes use of it within the SRD?

Was just taking a look again at the gist and noticed that your schema for Option has an attribute called prerequisites. It's clear to me what the purpose of this could be, but could you provide an example that makes use of it within the SRD?

Cleric gets "(a) a mace or (b) a Warhammer (if proficient)".

You can see how this is represented in the API currently using the prerequisites attribute:

https://dnd5eapi.co/api/classes/cleric/starting-equipment

Was just taking a look again at the gist and noticed that your schema for Option has an attribute called prerequisites. It's clear to me what the purpose of this could be, but could you provide an example that makes use of it within the SRD?

Cleric gets "(a) a mace or (b) a Warhammer (if proficient)".

You can see how this is represented in the API currently using the prerequisites attribute:

https://dnd5eapi.co/api/classes/cleric/starting-equipment

I see, thanks. That makes sense.

Now I'm just waiting for these changes to be implemented lol, I've already inserted the data structure into my own code since it's sort of all encompassing.

Now I'm just waiting for these changes to be implemented

As soon as I have agreement from the maintainers, I'll get to work.

Haha. I feel reasonably called out and I definitely deserve it. @fergcb I have no plans tonight after work so I'll dedicate it to this.

I agree with @Wyzards that type as a field name feels a bit overloaded and it has a different meaning depending on where in the structure you are. This could become quite confusing.

I agree with @ogregoire that OptionSet should probably not use the term resource_list. Perhaps api_reference instead of reference? That seems a little less vague. I kind of feel like resource_list_url isn't quite right either. And makes sense to use our ApiReference structure that we already have?

I also like choice, multiple, single as the options. I think that's a bit clearer.

@fergcb If it's not too much of a bother, can you update that gist with the changes we've agreed on so far? Just so it's easier to track where we are now that we've agreed on some things?

I also feel like the overloading of our usage of the type field might have been causing some confusion in the discussion.

That being said, just a friendly remind to try and keep discussions friendly and civil. We're all doing this for fun. Or at least... I'm doing this for fun.

That being said, just a friendly remind to try and keep discussions friendly and civil. We're all doing this for fun. Or at least... I'm doing this for fun.

This API is for blood, and blood only. No fun.

@fergcb If it's not too much of a bother, can you update that gist with the changes we've agreed on so far? Just so it's easier to track where we are now that we've agreed on some things?

In all seriousness though, what you said here would be great and make discussing this a lot more clear.

This API is for blood, and blood only. No fun.

Blood for the blood god. Skulls for the skull throne.

OptionSet should probably not use the term resource_list. Perhaps api_reference instead of reference? That seems a little less vague. I kind of feel like resource_list_url isn't quite right either. And makes sense to use our ApiReference structure that we already have?

@bagelbits the data corresponding to the type resource_list isn't an APIReference, and it can't be represented that way.

We already have the ResourceList structure, and that's that the URL links to. A ResourceList doesn't have an index or a name, just a URL.

I'm fine with all the other changes though :)

Okay! Then resource_list_url probably makes sense.

The gist has been updated to reflect the following suggested amendments:

  • The type attributes of Option and OptionSet objects have been renamed to option_type and option_set_type respectively, to more easily distinguish the difference between the structures from the programmer's perspective.
  • The array value of the option_type attribute has been changed to multiple, to help indicate that all of the items in the JSON array come with that option.
  • The resource_list value of the option_set_type has been changed to resource_list_url to better indicate the structure of the data: it is a string holding a URL that resolves to a ResourceList, not an actual ResourceList in its own right.

(@bagelbits @Wyzards)

That seems a little less vague. I kind of feel like resource_list_url isn't quite right either.

When I suggested resource_list_url I was referring to the attribute that stored the resource list url, not the name for the OptionSet type.

In that respect I thought the names array and resource_list were sufficiently descriptive. Now that my suggestion has been implemented in the wrong place its less accurate. @fergcb

When I suggested resource_list_url I was referring to the attribute that stored the resource list url, not the name for the OptionSet type.

@Wyzards this change was based more on @bagelbits suggestion later in the thread. I think changing the value of the option_set_type makes the most sense, because it's describing the structure of the data within, and the data is a URL, not a ResourceList. The url attribute could be renamed as well, but it wouldn't be as useful of a change by itself.

When I suggested resource_list_url I was referring to the attribute that stored the resource list url, not the name for the OptionSet type.

@Wyzards this change was based more on @bagelbits suggestion later in the thread. I think changing the value of the option_set_type makes the most sense, because it's describing the structure of the data within, and the data is a URL, not a ResourceList. The url attribute could be renamed as well, but it wouldn't be as useful of a change by itself.

Agree to disagree I suppose. Doesn't make too much of a difference to me in the long run.

Okay! Then resource_list_url probably makes sense.

No it doesn't.

I will translate that name exactly as it means:

Resource List Uniform Resource Locator

Why does anyone want to use twice the word "resource" in a single name? That makes no sense.

I strongly advise to use a different name that makes actual sense and that doesn't repeat.

Why does anyone want to use twice the word "resource" in a single name? That makes no sense.

I strongly advise to use a different name that makes actual sense.

The data the value is describing is a URL. That URL resolves to a ResourceList. Hence, resource_list_url.

Perhaps suggesting a suitable alternative would be a more productive contribution to the discussion?

Perhaps suggesting a suitable alternative would be a more productive contribution to the discussion?

I did, but you rejected it. At least in the sense that I suggested alternatives to resource list, which is the root cause of the issue.

All those lists are not resource lists. They're item lists, spell lists, etc. Using the global name resource for those is hype-y and not descriptive. Maybe we should use a global name such as game element for those, as they're part of the game and it's a fitting name to describe what both equipment items and spells are. And then we could have something akin to "game_element_list_url", or "element_list_reference". And I insist that reference is adequate (and better than URL) because it's a pointer, it describe that the list refers to something that is described elsewhere. The reference happen to be a URL, but it's still a reference. So my prime candidate for naming that field is "element list reference". What do you think of this? Oh, and please stop saying I don't suggest alternatives when in fact I did.

I did, but you rejected it.

Are you referring to your suggestion of "reference"? I hope it's clear after the following discussion why that isn't really an appropriate alternative.

Maybe resource list is not a good name then?

Maybe. I feel that's distracting from the goal of this proposal. If we decide to change the documented name of that structure, we can always revisit the use of its name in this structure. If you think it's truly that in-need of an update, you could open an issue about it on the API repo (where the docs live)?

I did, but you rejected it.

Are you referring to your suggestion of "reference"? I hope it's clear after the following discussion why that isn't really an appropriate alternative.

Maybe resource list is not a good name then?

Maybe. I feel that's distracting from the goal of this proposal. If we decide to change the documented name of that structure, we can always revisit the use of its name in this structure. If you think it's truly that in-need of an update, you could open an issue about it on the API repo?

I still think that resource_list is the most acceptable name. reference isn't sufficient because it points to a resource list, which is established in the documentation at https://www.dnd5eapi.co/docs/#resource-lists.

The option_set_type of the OptionSet essential refers to how the data is stored. In the case of the one that uses a resource list, I think that resource_list subsequently makes the most sense...

Same case for the array OptionSet type.

I'll also note that I agree, this is distracting from the goal of the proposal and could always be changed later.

I still think that resource_list is the most acceptable name. reference isn't sufficient because it points to a resource list, which is established in the documentation at https://www.dnd5eapi.co/docs/#resource-lists.

I'd be happy to revert to resource_list, my original proposal. That particular change was in response to @bagelbits' suggestion, so I'd be interested to hear their thoughts on the above few comments.

I still think that resource_list is the most acceptable name. reference isn't sufficient because it points to a resource list, which is established in the documentation at https://www.dnd5eapi.co/docs/#resource-lists.

That's... not exactly true. The resource_list you're referring to in the docs is for an index on an endpoint and is different shape than what we're calling a resource_list here, i.e. /api/equipment-categories/martial-weapons. I think @ogregoire has a point that resource_list_url doesn't quite feel like the right fit for what we're trying to convey. But I'm having a devil of a time thinking of something that works. Let me workshop this a little.

So this is how it stands right now:

"from": {
  "option_set_type": "resource_list_url",
  "url": "/api/equipment-categories/martial-weapons"
}

And previously we had this which also didn't feel quite right:

"from": {
  "option_set_type": "resource_list",
  "url": "/api/equipment-categories/martial-weapons"
}

Hrmmm.... my first thought is doing reference_list:

"from": {
  "option_set_type": "reference_list",
  "url": "/api/equipment-categories/martial-weapons"
}

If we wanted to be a little more verbose, we could even do:

"from": {
  "option_set_type": "reference_list",
  "reference_list": {
    "name": "Martial Weapons",
    "index": "martial-weapons",
    "url": "/api/equipment-categories/martial-weapons"
  }
}

Though, honestly, that feels a little weird because reference_list makes you think it's going to be a list of things but you're only giving an object. What do y'all think?

It seems like everything else is mostly solidified though and this is our last piece. I think my only other question is what do we gain by differentiating between single and multiple?

I still think that resource_list is the most acceptable name. reference isn't sufficient because it points to a resource list, which is established in the documentation at https://www.dnd5eapi.co/docs/#resource-lists.

That's... not exactly true. The resource_list you're referring to in the docs is for an index on an endpoint and is different shape than what we're calling a resource_list here, i.e. /api/equipment-categories/martial-weapons. I think @ogregoire has a point that resource_list_url doesn't quite feel like the right fit for what we're trying to convey. But I'm having a devil of a time thinking of something that works. Let me workshop this a little.

So this is how it stands right now:

"from": {
  "option_set_type": "resource_list_url",
  "url": "/api/equipment-categories/martial-weapons"
}

And previously we had this which also didn't feel quite right:

"from": {
  "option_set_type": "resource_list",
  "url": "/api/equipment-categories/martial-weapons"
}

Hrmmm.... my first thought is doing reference_list:

"from": {
  "option_set_type": "reference_list",
  "url": "/api/equipment-categories/martial-weapons"
}

If we wanted to be a little more verbose, we could even do:

"from": {
  "option_set_type": "reference_list",
  "reference_list": {
    "name": "Martial Weapons",
    "index": "martial-weapons",
    "url": "/api/equipment-categories/martial-weapons"
  }
}

Though, honestly, that feels a little weird because reference_list makes you think it's going to be a list of things but you're only giving an object. What do y'all think?

It seems like everything else is mostly solidified though and this is our last piece. I think my only other question is what do we gain by differentiating between single and multiple?

I thought of reference_list as well but thought it might not fit, since the documentation already names the structure "resource list" in addition to it including the count attribute, making it not literally just a list of references, as the name would indicate.

On the final note, I'm pretty sure we already agreed that there should be a distinction between single and multiple. I assume here you're referring to the three option types, single, multiple, and choice. I feel that these should be unchanged.

Also I think just the URL is fine rather than an entire reference to the resource list, especially since the endpoint already contains information that would be stored within said APIReference.

I thought of reference_list as well but thought it might not fit, since the documentation already names the structure "resource list" in addition to it including the count attribute, making it not literally just a list of references, as the name would indicate.

To clarify here, I have no problem with using reference_list here, although I don't see it as much more descriptive than resource_list`

I thought of reference_list as well but thought it might not fit, since the documentation already names the structure "resource list" in addition to it including the count attribute, making it not literally just a list of references, as the name would indicate.

Just to be clear, /api/equipment-categories/martial-weapons is not a resource list. If we look at the docs for equipment categories, it's just index, name, and a list of APIReference. Do we have any other examples of how we would use this field besides links to Equipment Categories? I think that might help a little with how we think about this specific case.

I thought of reference_list as well but thought it might not fit, since the documentation already names the structure "resource list" in addition to it including the count attribute, making it not literally just a list of references, as the name would indicate.

Just to be clear, /api/equipment-categories/martial-weapons is not a resource list. If we look at the docs for equipment categories, it's just index, name, and a list of APIReference. Do we have any other examples of how we would use this field besides links to Equipment Categories? I think that might help a little with how we think about this specific case.

You're correct, this is not a resource list, that's my mistake. If starting equipment is the only application of the resource_list option-type, then resource_list would not be appropriate.

I looked a little through the SRD to find any other places where a Choice option or resource list OptionSet would need to be used, but couldn't find any. However, my search was by no means thorough and it doesn't seem completely unlikely that there would have to be a nested choice that actually does refer to a resource list.

If starting equipment is the only usage of this OptionSet type, then I think reference_list would actually be the most appropriate.

I don't know how I missed that an equipment category endpoint doesn't return a ResourceList... That complicates things somewhat, and it's completely on me for not checking 😬

I don't feel then that something like reference_list would be appropriate, given that resolving the value doesn't give you a list of references, or a generic structure that would be easy to extract a list of references from. The options are under the equipment attribute of the returned document, which is obviously very specific to equipment categories. Even if we named the resource_list type more appropriately, it'd still be unique to equipment categories.

This makes me feel that it would be worth going even more specific and creating a new option_set_type called equipment_category? And we could use a full APIReference like bagelbits suggests. Going this specific increases the complexity for consumers a little bit, but starting equipment is probably one of the most important places where Choices are used, so I feel it would be acceptable.

My thinking behind resource_list was that it could be used to include query params in the URL to filter a ResourceList. For example, the Choice in the High Elf's wizard cantrip trait could be from the ResourceList returned by /api/spells?level=0&class=wizard.

Of course, at the time I was assuming that equipment categories returned ResourceLists, which we've now learned is wrong, so that approach is now less generalisable. But I think there may be some value in introducing it alongside a equipment-category type.

I don't know how I missed that an equipment category endpoint doesn't return a ResourceList... That complicates things somewhat, and it's completely on me for not checking 😬

I don't feel then that something like reference_list would be appropriate, given that resolving the value doesn't give you a list of references, or a generic structure that would be easy to extract a list of references from. The options are under the equipment attribute of the returned document, which is obviously very specific to equipment categories. Even if we named the resource_list type more appropriately, it'd still be unique to equipment categories.

This makes me feel that it would be worth going even more specific and creating a new option_set_type called equipment_category? And we could use a full APIReference like bagelbits suggests. Going this specific increases the complexity for consumers a little bit, but starting equipment is probably one of the most important places where Choices are used, so I feel it would be acceptable.

My thinking behind resource_list was that it could be used to include query params in the URL to filter a ResourceList. For example, the Choice in the High Elf's wizard cantrip trait could be from the ResourceList returned by /api/spells?level=0&class=wizard.

Of course, at the time I was assuming that equipment categories returned ResourceLists, which we've now learned is wrong, so that approach is now less generalisable. But I think there may be some value in introducing it alongside a equipment-category type.

I have no objections to this.

@fergcb I'd love to see an example of where we actually use a resource list as well. Also, how does this structure work with other places we use choices, like monsters for example?

I'd love to see an example of where we actually use a resource list as well.

@bagelbits Currently, we don't. Like I explained in my previous comment, I was initially working under the assumption that equipment categories returned ResourceLists, but under the realisation that they don't, I think there still could be value in supporting them as a source of Options for a Choice; we could use this for choosing languages (where we could just refer to the /api/languages ResourceList, rather than listing every single language as APIReferences), or the high elf cantrip example I gave earlier (/api/spells?level=0&class=wizard [although now I think of it, I'm not sure the class query param exists on the spells endpoint - maybe it should]).

Also, how does this structure work with other places we use choices, like monsters for example?

This raises a good point that not all things being chosen from are references to other documents, though I think Monsters' attacks are unique in that regard? Class and Background StartingEquipment, feature/trait choices, proficiency choices, and spell choices, etc. all only use APIReferences (and therefore work the exact same way as the StartingEquipment example given), so I must have skimmed over multiattacks being different.

To handle Monsters' multiattacks, we'll either have to split the single Option type into something like reference and attack, or change the way monster attacks work. The former seems favourable.

I would love to see some examples of that then! And we might want to scour the rest of our choice usage to make sure we aren't missing any other edge cases. πŸ˜„

Apologies for the inactivity; it's a busy time for me rn.

I've updated the schema in the following ways:

  • Reverted the resource_list name change, and changed the attribute from url to resource_list_url, as per @Wyzards' suggestion.
  • The equipment_category OptionSet type has been added to support equipment categories properly (which have a structure distinct from ResourceLists). EquipmentCategories are now linked with an APIReference.
  • The single Option type has been split into reference and action. The reference type is identical to the previous single type, corresponding to a counted APIReference. The action type is intended for use within "Multiattack" actions, referring to actions, by name, within the same Monster document. An example based on the "Captain" monster has been added to the Gist (@bagelbits).

@fergcb just got the chance to look at your changes.

Obviously I agree with the first change. I also agree with equipment_category being its own OptionSet. As for splitting single Options, there's a couple nitpicks I have but overall I agree with the idea.

First of all, I feel that the Option type currently named reference should stay as single. It just seems more intuitive to me personally. Additionally, the top-level options attribute within the Multiattack Action you provided should be named something along the lines of choice, action_choice or attack_choice, since the attribute contains a choice, not a list of options. Finally, I think it could make more sense for the new option's type to be "attack" instead of "action". I can't really see this new option being used outside of attacks. If I'm wrong, please provide an example to correct me. If that is the case, then "action" is an appropriate name.

Otherwise, I think this newest rendition looks great.

First of all, I feel that the Option type currently named reference should stay as single.

That feels misleading, as actions may also be "single" items in the choice.

the top-level options attribute within the Multiattack Action you provided should be named something along the lines of choice, action_choice or attack_choice, since the attribute contains a choice, not a list of options.

I haven't changed/added anything, there. That attribute already exists in action objects. Changing that is unrelated to the Choice structure itself and belongs in a separate issue.

I think it could make more sense for the new option's type to be "attack" instead of "action". I can't really see this new option being used outside of attacks. If I'm wrong, please provide an example to correct me. If that is the case, then "action" is an appropriate name.

Dragons use their Frightful Presence action as part of their multiattack:

Multiattack. The dragon can use its Frightful Presence. It then makes three attacks: one with its bite and two with its claws.

I think it could make more sense for the new option's type to be "attack" instead of "action". I can't really see this new option being used outside of attacks. If I'm wrong, please provide an example to correct me. If that is the case, then "action" is an appropriate name.

Additionally, this structure will get reused for Legendary Actions, which are currently not broken out. I think there's an open issue for it.

IIRC how Legendary Actions work.

If that's the case, then I have no other issues with this proposal.

I'll try to review this again later tonight so we can get cracking on this and unblock everyone.

I think that looks good. @ogregoire do you have any additional feedback before we try and roll this out?

I still dislike the word array. The rest seems to have been properly iterated upon.

We use resource_list which indicates a string but refers to some other data which are resource lists. So that's fine.
We use equipment_category which indicates an API reference that refers to some other data which are equipment categories. So that's fine.

Then we use array which indicates an array of options but the type just calls it array. It's not an array, it's an array of options. So that's not fine.

We have two elements that are defined by what they will contain, and one that is defined by its json-type. That's inconsistent. If we want consistency, but keep array, we could rename the other two string and object, respectively. (Please don't, that was for the purpose of the argument.) I don't see why the work is good for two out of three, but for the third, we just stop caring about proper naming.

For the rest, I totally agree. It's a clear improvement: I can read the JSON and understand it without checking the type definitions.

@ogregoire Keeping with the theme. Would it make more sense to call it options instead of array?

Yes, I'm glad someone else thought of that name. options is perfectly fine. option_list as well. option_array is not consistent because then we'd sometimes use list and other times array. So yes, please, use options, that's my request from day 1.

option_array is not consistent because then we'd sometimes use list and other times array.

option_list would be misleading when contrasted with resource_list, as a ResourceList is structurally very different from an Array of Option objects. If one saw an option_list was an Array of Options, they would expect a resource_list to be an Array of Resources, which it is not.

options also feels like a bad choice given that all of these structures resolve to a selection of options to be chosen from.

options_array appears to be the best choice, to me. It describes clearly that the underlying data is a JSON Array ("Array" being the accepted standard word for that data type in JSON, not "List") containing Options.

I imagine this conversation:

  • John, you must choose between blue, red and yellow.
  • Can I choose green?
  • No, green is not on the array.

That doesn't feel right.

  • John, you must choose between blue, red and yellow.
  • Can I choose green?
  • No, green is not on the list.

Now, this sounds way better!

Actually, I don't see an example of using resource_list. Is there one that exists?

I imagine this conversation:

  • John, you must choose between blue, red and yellow.
  • Can I choose green?
  • No, green is not on the array.

That doesn't feel right.

  • John, you must choose between blue, red and yellow.
  • Can I choose green?
  • No, green is not on the list.

Now, this sounds way better!

Green is not in the array. Of course it sounds weird if you use the wrong preposition.

Actually, I don't see an example of using resource_list. Is there one that exists?

We've talked about a few examples earlier in the thread. I can draw up some demo JSON later.

Sorry @fergcb if you don't mind when you have time.

I think aside from the correct name for array, this looks golden.

@ogregoire Also, to @fergcb's point, it would be No, green is not in the array. and No, green is not (in|on) the list. but that's linguistic semantics. Both of which are understandable and valid.

Well, let's look at our raw material, the SRD.

Page 57:

one skill from the class’s skill list

Page 143:

Choose one of the forms from the above list. (Present twice)

Page 152:

Choose the effect from the following list, or choose an effect offered by the GM.

On the other hand, array is mentioned only one time in the whole document, on page 125:

A dazzling array of flashing, colored light springs from your hand.

So basically, four out of the 94 times the word "list" is mentioned is in direct relation with choice, and the only time the word "array" is mentioned at all, it's only for in-game description, not for rules.

So yes, "list" is more suitable than "array".

....language is hard.

In this case, I'd argue that the wording in the SRD is almost entirely irrelevant. If the programmer is faced with option_list and resource_list we should not expect them to have an intimate knowledge of how the SRD phrases things in order to interpret these type descriptors.

Remember, the programmer is faced with the type attribute. Not the end user. The programmer would be better off being able to infer from the value option_array that the underlying data is an Array of Options, rather than having to pick apart the difference between an option_list (an Array of Options) and a reference_list (a URL string pointing to a ReferenceList object).

I'll list the options below. The first is the most explicit and the most descriptive, to me. The second is entirely misleading, by the use of list implying that the structures are similar, which they are not. The last is much less verbose than the first, but is at least less contradictory than the second.

option_array = Array of Option objects
resource_list = URL resolving to a ResourceList object

option_list = Array of Option objects
resource_list = URL resolving to a ResourceList object

options = Array of Option objects
resource_list = URL resolving to a ResourceList object

@fergcb

I'm not asking to rename array to option_list: it was one suggestion out of two, and I left the list of suggestions (not array) open. If you don't like option_list, why don't you like options? What is irremediably wrong about options?

I don't want array, you don't want list. Why can't we settle on options?

I addressed options in my last post. In two of my last three posts, in fact.

No, you didn't. At least not in your last few posts. You did in one of your first posts. And in there, you said:

The solution to this is not to give the attribute a value of options. That does not describe the structure of the data.

You're still wrong. The "s" of "options" imply the structure, saying that there are multiple options. And what address the plurality in json? The array. So options describes perfectly the underlying structure! Am I the only one to see that?

Plus, the number of times we use in this API a plural to say that we have a JSON array is huge. We use prerequisites, we use proficiencies, class_levels, etc. Should we change all of those to have array, array and array? Should we change all of them to have prerequisite_array, proficiency_array and class_level_array? No: we should keep them as is.

The appropriate word here is options, not array and you still have no explanations for your refusal to use it.

There's little value in comparing attribute names (e.g. prerequisites, proficiencies, etc.) with the value of the type attribute .

This value is supposed to describe the structure, for the programmer, not to be a "name" for the underlying value. That's what the attribute name does. I have been clear and consistent on the purpose of the type attribute from the start. It is not a name. It is a type; a description of the object's structure.

you still have no explanations for your refusal to use it.

I will list my objections, directly quoting from previous comments in this thread, below.

The last [referring to options] is much less verbose than the first [option_array], but is at least less contradictory than the second [option_list].

options also feels like a bad choice given that all of these structures resolve to a selection of options to be chosen from.

I feel these two very recent comments summarise the key objections well enough, though I'm sure if you scroll back far enough, or check previous issues where we've talked about Choice reforms, you may find further comments about this. If you need any clarification I can try to expound upon these points, but to suggest that I haven't offered any objection at all is untrue.

I will list my objections, directly quoting from previous comments in this thread, below.

The last [referring to options] is much less verbose than the first [option_array], but is at least less contradictory than the second [option_list].

That's not an objection: it's the opposite, an endorsement for options.

options also feels like a bad choice given that all of these structures resolve to a selection of options to be chosen from.

No: there are the plain options that we could call, you know, options, and then there are the other types that are called resource_list and equipment_category.

You keep speaking about programmers versus data users, well let me break it to you: attribute names, type names and type hints (the content of the type attribute) are all present exclusively for the programmer. Yet, you seem to make a hierarchy between those and allow for different rules when in fact they're all only programmer helpers. So yes, there is value in comparing attribute names to type hints.

Tonight I keep having logical explanation over logical explanations, yet you seem to entirely disregard those for the sake of "I said so". I don't want to lose my energy to naysayers today. So if you want to use array, just do it. I'll do the rewriting after you're done.

Edit: my last sentence could be badly taken in this project, but I actually meant in my personal copies where I actually use the data. Sorry for the possible misunderstanding.

That's not an objection: it's the opposite, an endorsement for options.

It is an objection. I believe verbosity is a positive quality in this case. Certainly the latter half of my statement is an "endorsement" over option_list, but not over option_array.

No: there are the plain options that we could call, you know, options, and then there are the other types that are called resource_list and equipment_category.

ResourceLists and EquipmentCategories both present collections of options (in the regular spoken/written English sense of the word "options") for the Choice.

You keep speaking about programmers versus data users, well let me break it to you: attribute names, type names and type hints (the content of the type attribute) are all present exclusively for the programmer. Yet, you seem to make a hierarchy between those and allow for different rules when in fact they're all only programmer helpers. So yes, there is value in comparing attribute names to type hints.

I mentioned the values here being programmer facing simply to reinforce the idea that verbosity is a positive thing, here. Given that the data is in a JSON Array, how does it detract to say that the type of this particular option set is an option_array? That value conveys two useful pieces of information to the programmer: the value is an array, and the array contains Option objects. Sure, options kind of implies that, but less explicitly. What's the benefit in leaving that ambiguity? You yourself have expressed that you don't like checking the docs, so why not let the data be self-documenting?

Tonight I keep having logical explanation over logical explanations, yet you seem to entirely disregard those for the sake of "I said so". I don't want to lose my energy to naysayers today. So if you want to use array, just do it. I'll do the rewriting after you're done.

If you think that my tireless expansion, redevelopment and reiteration of this proposal boils down to me saying "I said so", then I believe you are contesting this in bad faith. I challenge you to find an example of me indicating that this proposal should pass because "I said so". Not only have I taken most all of the criticism on board and made amendments to the proposal where agreed upon, I have welcomed, sought out, and taken on-board opinions from all of the contributors.

I said "you win", take it.

I said "you win", take it.

It's... not a competition, I'm not trying to "win". See my previous comment RE: bad faith, I guess :/

Y'all, I go away for checks watch four hours... please. This is a silly project that I, personally, like to spend my free time on for fun. It's not that serious. It's not a contest that someone has to win.

That being said. After reviewing this, I think we should go with option_array.

options while being accurate is also vague when it's all options
array is fine but honestly pretty vague
option_list is going to confused with reference_list which is a very different data shape. The only way I can see this one working is if we call reference_list something else which I assume isn't going to happn.

I feel like option_array works as a decent compromise. If you want to change it options or array in your own personal projects, please feel free.

@ogregoire @fergcb I'm sorry. My company is launching it's first store tomorrow and I'm a little shorter on patience than normal and that is not fair to either of you.

@ogregoire I would like to remind you that there is a Code of Conduct for this repo. You can review it here. Please reach out to me privately if you would like to discuss this further.

@fergcb I want to call out a huge thank you for driving this discussion. I know Choices have been a pain point for a lot of users and this is a huge undertaking to champion. This will also unblock a few other projects once we get this in.

@fergcb Thinking about this a little bit more, option_list could work if we called it reference_list_url instead. I think that reference_list_url would more accurately model the data since it will be a url to a reference list.

Also, come to think of it, we use list to describe arrays in our documentation. Which also lends credit to using option_list as well.

Also, come to think of it, we use list to describe arrays in our documentation.

Which feels like a bad thing, given that the API serves JSON and there's no such thing as a "list" in JSON.

@fergcb Thinking about this a little bit more, option_list could work if we called it reference_list_url instead. I think that reference_list_url would more accurately model the data since it will be a url to a reference list.

I don't like this because (a) the reason above - lists aren't a JSON concept, and (b) the set of options itself isn't a URL, it's a ResourceList. We just provide the URL so the consumer can fetch the actual ResourceList object.

We just provide the URL so the consumer can fetch the actual ResourceList object.

But isn't it still a URL? So by that logic, wouldn't reference_list_url make the most sense? Also do we have an example of this? I think a lot of the confusion all of us are having is due us not even knowing what this looks like in practice.

Which feels like a bad thing, given that the API serves JSON and there's no such thing as a "list" in JSON.

I don't think we've done any of our field naming based on JSON types up this point? All of our naming conventions have been based on the SRD?

Additionally, if we use reference_list_url, it makes it really easy for an end user to make a reference_list method that just fetches the reference_list based on the reference_list_url.

I can understand naming attributes and such after things in the SRD when they align nicely, but the type names of generic structures like Arrays seem like they should live outside the realm of SRD knowledge and should be designed to help the consumer deserialise the JSON. (ETA: see my previous comment regarding how we shouldn't expect the consumer to have an intimate knowledge of how things are worded in the SRD just to fetch the data) Especially in the docs. E.g. if I'm looking at the docs figuring out how to process a certain property, it would be more obvious if I was told that the property's value was an array, rather than a list. The org.json library for Java would parse the data as a JSONArray, for example. Or more obviously, perhaps, JavaScript would give me an Array.

I can only apologise for a lack of an example so far, I've been unbelievably busy. I'll draw one up now, it's relatively straightforward.

One of the examples I gave previously was referring to the entire languages collection for Background language choices, rather than listing each language separately. This would make maintenance much easier. It would look like this:

{
  "language_options": {
    "desc": "any 2 languages",
    "choose": 2,
    "type": "language",
    "from": {
      "option_set_type": "resource_list",
      "resource_list_url": "/api/languages"
    }
  }
}

As you can see, the option_set_type of "resource_list" indicates that the options are contained within a ResourceList (just as "options_array" indicates that the options are contained within an Array of Option objects), and then the attribute resource_list_url is given to allow that ResourceList to be fetched.

Thank you for providing an example, that makes it much easier to visualize. And thank you for taking the time to do that given how busy you are. I really think we should call the type resource_list_url instead of resource_list, since it is literally a url for the reference list.

And given your points on array vs list, I can see the benefit of having generic types not tied to the SRD but the JSON concepts. So I think we should go with my initial suggestion of options_array. Thanks for talking that one out with me some more. As an aside, we should probably clean up the docs to say array instead of list to conform with JSON naming conventions.

I really think we should call the type resource_list_url instead of resource_list

It feels weird to revert back to that after people didn't like it the first time it was changed to that, but if that's really what you think is best, I'm happy to go back to it. I don't have any strong feelings against it other than not aligning with the original purpose of that field πŸ˜…

Thanks for talking that one out with me some more.

No problem! It's something that's bugged me for the duration of this discussion and long before, so I'm glad I was finally able to find the right words to put the point across. I'll update the gist to include the options_array change when I can.

Frankly, resource_list is just a weird one to model correctly.

It's fairly similar to equipment_category. If we're going to go for resource_list_url, do we need to go for equipment_category_reference?

I mean, a level of verbosity is good but this is getting unwieldy πŸ˜…

Nah. I think equipment_category_reference would be silly. equipment_category matches how we do APIReferences everywhere else. We could rename it to api_reference if we wanted to be pedantic though and have it be more generic.

Calling it resource_list only feels like it would make sense if we did this:

"from": {
  "option_set_type": "reference_list",
  "reference_list": {
    "name": "Martial Weapons",
    "index": "martial-weapons",
    "url": "/api/equipment-categories/martial-weapons"
  }
}

We could call it reference_list_reference though 🀣

I agree, equipment_category_reference is a bit silly. Also, api_reference doesn't work, because the option_set_type needs to indicate how the resulting data should be treated. I'm not aware of any other Documents that can be pointed to by an APIReference that would make sense to support as OptionSets, but each would have different steps needed to extract the options. For example, an EquipmentCategory has its options as an array of APIReferences under the equipment attribute.

equipment_category matches how we do APIReferences everywhere else

Doesn't resource_list match how we do URLs everywhere else, in the same way? E.g. spells in Class documents. Though, bear in mind the difference between the value of the type attribute and the names of attributes elsewhere in the database means such comparisons might not be that useful.

Calling it resource_list only feels like it would make sense if we did this:

Resource lists aren't Documents that can be referenced with APIReferences like that, sadly. They don't have names or indices.

However, I wonder why you feel that it would make more sense if it was an APIReference, but not a more generic reference by URL?

Yeah. That makes sense why api_reference wouldn't work for equipment_category

E.g. spells in Class documents.

I actually wonder if we should do to spells in Class documents the same thing we still need to do with class_levels. Probably can add that to what still needs to be done in #251

However, I wonder why you feel that it would make more sense if it was an APIReference, but not a more generic reference by URL?

It's kind of a feeling thing? I think other than the places you have mentioned in Class, which honestly need to be cleaned up still, every time we have a value of a url, the key is url. Mostly this is due to almost everything using an APIReference. However, it feels more consistent that way. And the top level key for an APIReference is always a reference to something in the SRD. The term url is our way of designating a reference to another part of the DB or API.

Yeah, spells could be put in the Class document directly.

You mention that every time there's a URL (besides that one example), the attribute name is url. You'll notice that in this proposal, the name of the attribute holding the URL for a ResourceList actually was url, but we changed it to resource_list_url to make it extra obvious.

The value of the option_set_type attribute is different to the name of the separate attribute that contains the URL. The type of the thing containing the options (the option_set) is a ResourceList, not URL/string. Hence, "option_set_type": "resource_list". However, it would be unwieldy and difficult to maintain to put a whole ResourceList in the Choice structure, so we let the consumer resolve it themselves, and we give them a URL to do that. We call the attribute holding that URL resource_list_url to make it clear and somewhat self-documenting.

It's the same reasoning behind equipment_category: the EquipmentCategory is the thing containing the options, so it would be weird to say the type of the option_set was a reference to that category. The only difference is that we call the attribute containing that reference equipment_category rather than something like equipment_category_reference for consistency with the rest of the repo. Originally that attribute was just called reference (as seen in Proficiencies), but that didn't seem like it would be popular given the distaste for url in the resource_list option set.

I hope I'm explaining this okay.

Yeah I think you are. However, I want to point out that the value of the option_set_type attribute is inherently arbitrary and we are just trying out to figure out the semantics of an ENUM that makes the most sense.

The type of the thing containing the options (the option_set) is a ResourceList, but it is shown using a URL/string. I think that's the distinction I'm trying to make here. resource_list would make more sense if we were to put the whole ResourceList in the Choice structure. But instead, we're putting a reference. That is different from the ResourceList itself.

Heh. It's hard to keep track of the various iterations of this discussion.

resource_list would make more sense if we were to put the whole ResourceList in the Choice structure. But instead, we're putting a reference. That is different from the ResourceList itself.

I'm afraid I really do struggle, then, to see why EquipmentCategory/equipment_category is acceptable, but ResourceList/resource_list isn't? They both contain references to objects with those types. An APIReference is pretty much as different from an EquipmentCategory as a URL is from a ResourceList.

The fact that the URL is given rather than the full object is clear from the attribute on the object being called resource_list_url. The docs can make it even clearer that both the equipment_category and resource_list types first need to be resolved with an additional request, if it isn't clear enough from the attribute names.

I feel like I've said this already, but I think api_reference makes more sense than equipment_category if we wanted things to be generic for a type. I don't exactly see it as the most acceptable solution but I'm willing to make the compromise for it. Just because EquipmentCategory is the only current use case for it, doesn't mean that it's the only future use case for it.

As I mentioned previously, EquipmentCategory is the only use-case for it. EquipmentCategories store their options as an array of APIReferences in the equipment field. And if the consumer is using a typed language, they're gonna want to deserialize the data they fetch from that reference as an EquipmentCategory so that they can handle that. The same can't be said for any other Document that can be referred to with an APIReference. If the option_set_type was api_reference, which doesn't indicate any information about the option set's type, the consumer would have to infer the type themselves.

Hopefully this illustrates the purpose of the option_set_type attribute: to indicate the structure, and therefore the steps needed to deserialize and access, the actual object containing the options. The name of the attribute(s) under that (should) adequately indicate that we're providing a reference rather than the object itself.

Now of course resource_list_url does indicate that the resulting option set is a resource_list, but the _url suffix is redundant (as it is already indicated by the resource_list_url attribute), and introduces inconsistency between resource_list_url and equipment_category.

Now, if we were going to push that purpose to one side in favour of only indicating the immediate type of the data in this Choice structure, and not the type of the option set, then we'd need to include more information in the object to help the user decode the result of resolving the reference. For example:

{
  "option_set_type": "api_reference",
  "document_type": "equipment-category",
  "reference": { "index": "..." }
}

This increases the complexity of the structure somewhat, to solve a problem that doesn't really seem to exist? Even if we did discover a need for more APIReference resolving to different kinds of OptionSets, it would be just as easy to add a new value for option_set_type as it would a new value for document_type (or whatever that attribute would be named).

Fine. You seem to know exactly what you want built. You should just do it. I'm tired of discussing this and I'd rather just have it be done. We can always revisit this later.

Oh... ok. I was happy to continue discussing this until we find a solution that works for everyone, but I don't wanna push my luck. Did you have any thoughts about the suggestion I made in my last comment at all?

I didn't come into this knowing what I wanted to build besides having a couple of end goals: consistency and "deserializability". The proposal has already changed so much since the first draft thanks to input from yourself and others. So thanks for that :)

I'm sorry. I should not have written that last response right before going to bed. It was passive aggressive, which was unwarranted for the discussion we were having. That response was also unkind and unfair to you. I should be better than that. It was also hard to tell that you were enjoying the discussion and not just getting frustated, but honestly, there was a better way to do that which was just to reach out to you directly over to Discord to check in, which I should have done. Instead I just shut down a discussion that I didn't need to shut down. I'm sorry.

I can see what you mean by equipment_category vs. api_reference and I remember you making a similar argument before and I believe that you are correct. And I think based on what you're saying, resource_list makes sense and we should just go from there.

I don't think I had considered "deserializability" in our discussions but I can see where you're coming from by mentioning that.

No worries.

I'll update the Gist with the latest amendments, but it may be some time before I can actually see the implementation through. If someone else would like to pick it up in the meantime, they'd be more than welcome.

@Wyzards Unless you want to take a crack at it, I might.

I've updated the Gist and added a summary of the final state of the proposal to the end of the original comment, as a sort of implementation guide for whoever picks this up.

Very late note, but I've been asked to include this finding here.

This structure will have some issues handling the choices for Ideals, Flaws, Bonds and Personality Traits stored within Backgrounds. Two types of single option must be added in order for these to be used as Options. An "ideal" option will be needed in addition to the "reference" and "action" OptionTypes. Additionally a "string" OptionType will be needed to use Personality Traits, Bonds and Flaws since all of these are just strings.

Fairly self explanatory, just other option types. This would leave us with singular option types of action, reference, ideal, and string

For any unaware, Ideals are not just strings. Here's an example of an Ideal in the Acolyte background.

{
        "desc": "Power. I hope to one day rise to the top of my faith's religious hierarchy.",
        "alignments": [
          {
            "index": "lawful-good",
            "name": "Lawful Good",
            "url": "api/alignments/lawful-good"
          },
          {
            "index": "lawful-neutral",
            "name": "Lawful Neutral",
            "url": "api/alignments/lawful-neutral"
          },
          {
            "index": "lawful-evil",
            "name": "Lawful Evil",
            "url": "api/alignments/lawful-evil"
          }
        ]
      }

I'm just going to assign this to myself to own it, since I'm not sure it will get done otherwise.

Is this actively being worked on? I'm writing an app that consumes the API, so if the choice structure is going to be changed soon I may have to avoid working with them.

Also, if no work is being done on this currently, I may be able to do it. I need this to be done before I can finish working on an API issue anyway.