smart-on-fhir / smart-scheduling-links

Clinical Appointment Slot Discovery
29 stars 15 forks source link

Add the dose number extension to the Slot. #36

Open cooperthompson opened 3 years ago

cooperthompson commented 3 years ago

Having dose number on Schedule is fine, but can we also put it on Slot? That way if a Schedule supports both dose 1 and 2, but on a specific day, they are only doing dose 1, we can represent that.

jmandel commented 3 years ago

This makes sense for me; the semantics would be that if a value is present on Slot, you can ignore the value on a Schedule (i.e., Slot values override Schedule values)? I like this, though it adds some complexity and it's worth checking that consumer-facing tools could/would be able to use this.

@Mr0grog do you have a take?

Mr0grog commented 3 years ago

Hmmm, that definitely does make consuming things more complex — is there a meaningful difference between a schedule with both doses but some slots only having one, vs. multiple schedules each with only the relevant slots?

I’m not sure it makes a huge difference for my use cases (aggregating availability across all providers in a region to help people find an available appointment quickly). We don’t currently show slot-level detail for anything, because they’re so frequently gone by the time someone goes through all the screeners and interstitial bits at the actual booking site. (That might be less of a problem as supply continues to improve.) Anyway, there’s no reason we can’t look at it both ways; it’s just a little more complicated.

FWIW, I never use the SMART Scheduling Links format directly — when we have clients displaying things, it always gets converted to converted to something much less verbose, more purpose driven, and that combines it with other data sets. The biggest concern I have here is that slot-level dosage extensions might really inflate the size of slot files. But since we don’t send this format to clients, it’s not likely to be a real problem in practice.

(As a side note: our biggest friction with the spec is more the other way around — since we don’t show slot-level detail, we often need a schedule-relevant booking link. In practice, that’s not a huge deal since we haven’t had any providers with links that are actually slot-specific, but it sounds like Epic will, and that’ll be something new for us.)

Mr0grog commented 3 years ago

If helpful, we keep several forms of the data internally (because the level of detail we are able to get varies so widely), and for the slot-level one, we store this info only on the slot:

{
  available: "yes" | "no" | "unknown",
  products: <string[]>,
  dose: <string>, // first dose, second dose, all doses, etc.
  capacity: [
    // Array of objects for each (day, products, dose) combination:
    {
      date: "<datestamp>",
      available: "yes" | "no",
      available_count: <int> | null,   // absent if unknown, e.g. in CVS's data
      unavailable_count: <int> | null, // absent if unknown, e.g. in CVS's data
      products: <string[]> | null,     // absent if unknown
      dose: <string> | null            // absent if unknown
    }
  ],
  slots: [
    // Array of objects for each (start, products, dose) combination:
    {
      start: "<timestamp>",
      end: "<timestamp>" | null,    // absent if unknown
      available: "yes" | "no",
      products: <string[]> | null,  // absent if unknown
      dose: <string> | null         // absent if unknown
    }
  ],
  source: <string>,
  valid_at: "<timestamp>",
  checked_at: "<timestamp>"
}
cooperthompson commented 3 years ago

The reason we are asking for this is that it lets us represent our capacity more accurately. If we split dose 1 and dose 2 onto different schedules, then the capacity for both schedules would be shared, so it looks like we have double the capacity that we actually do. Our capacity is already an estimate, but we are trying to keep it as specific as we can.

Mr0grog commented 3 years ago

If we split dose 1 and dose 2 onto different schedules, then the capacity for both schedules would be shared

Ah, from reading the spec language, my understanding was that you should have different slots in those two schedules, and if you have slots that support both doses, those would only show up on a separate, third schedule that is annotated with two dose extensions.

cooperthompson commented 3 years ago

We are doing coarse (day level) slots with per-slot capacity. So if we do a three schedule solution, then we'd be triple reporting capacity.

Mr0grog commented 3 years ago

Wouldn’t the same rule apply, though? You’d only count the capacity in those slots that applies to the given schedule configuration, e.g. if you had a day with 10 Moderna first doses and 10 Moderna second doses and 25 more Moderna shots that OK to give as either dose, you’d just have 3 schedules, each with one slot and capacities of 10, 10, and 25?

I feel like I must be missing what you're getting at. Can you make the example more concrete?

jwjahns commented 3 years ago

Hello, I've also been working with Cooper on this.

Using your example implementation, one thing I'm not sure how to resolve are busy Slots. Since busy Slots by definition don't support any doses, I'm not sure what Schedule it would use. A given Slot could "change" Schedules as follows:

Slot is available for dose 1 and 2 -> Schedule A After some reservations, Slot is only available for dose 2 -> Schedule B All reservations are filled, so Slot is now busy -> Schedule A?

If, instead, dose number information was on the Slot, then the Slot could stay connected to the same Schedule for its entire lifespan - and as dose numbers become unavailable, they're simply removed from the Slot's extension.

jmandel commented 3 years ago

If you track "dose 1 slots" and "dose 2 slots" separately (like, in your system you might go from "we can deliver a 1st or 2nd dose at noon next tuesday" to "We can only deliver a 2nd dose at noon next tuesday", then the current recommendation is to host a 1st dose Schedule and a 2nd dose Schedule, and represent two separate slots. I don't see why you'd introduce a third schedule.

I'm not against annotating Slots with additional details here, just wary of the jump in complexity for clients who need to understand these "context conduction" semantics (taking defaults from a Schedule, overriding them with values on a Slot).

jwjahns commented 3 years ago

Say we have a slot X with 100 capacity that supports both 1st and 2nd doses. If I understand right you're saying:

Schedule A: Dose 1, holds Slot X1 with 100 capacity Schedule B: Dose 2, holds Slot X2 with 100 capacity

In this scenario, Slots X1 and X2 share the same capacity but this is not communicated in any way. The result is we show double capacity. If a booster dose is added, we'll show triple capacity, and so on.

In the 3-Schedule situation, this is avoided. We would then only have Schedule C: Dose 1 and Dose 2, holds Slot X3 with 100 capacity

But then we run into issues with this 3rd schedule as noted above.

jmandel commented 3 years ago

From our earlier discussions about supply though, this kind of capacity estimate is already limited -- if I understood right from Cooper's earlier examples, I might see slots for times all week long that suddenly disappear all at once when a single appointment is booked that "takes" the last bit of remaining supply?

It might help to understand what factors would lead a slot to change from "1st or 2nd dose" to "2nd dose only" -- this is opaque for me right now.

jwjahns commented 3 years ago

Here's a scenario from a developer:

Organization has a small Clinic lab that has 100 doses worth of a vaccine to offer for this week. They are confident they will have the supply to cover any number of dose 2 needs in 3 weeks, but they don't want to fully expose all 100 shots to be all dose 2, so they plan for 1-100 Dose up and would allow 10 new dose 2 to come in if needed. If they reach all their dose 2 values they will give 90 total dose 1.

This would be 100 Vaccine available with both dose 1 and 2 available.

Now if we get 20 scheduled Dose 1s and 10 scheduled Dose 2s we would be looking at 70 remaining openings remaining for dose 1 with 30 total scheduled doses.

if we showed those as separate schedules it would look like this.

We have 100 openings that can accommodate vaccine for dose 1. (Remember we are looking at opening for the vaccine not specific to the dose. any one of those slots could be dose 1)

We also have 100 openings that can be dose 2. All those openings can be used but when we reach 0 we don't want to put more into the slots.

Sending multiple schedules here really doesn't make much sense. The delineating factor is not Dose 1 or Dose 2 but the actual vaccine itself. if we used 2 or 3 schedules to say this we would be sending 200 or 300 to start.

Instead the ideal communication would be to send 1 schedule and say dose 1 and 2 are available with 100 openings. When the above example 30 are scheduled and the dose 2 is no longer available we would like to send 1 schedule with 70 opinions but only dose 1 can be used now.

jmandel commented 3 years ago

Thanks. I'll say this kind of consideration highlights the value in pushing these attributes onto Slots all the time, rather than tracking them at the Schedule level. Still, we don't to break existing publisher implementations by mandating this kind of change.

Now, if we did allow dose number extensions on Slots, we'd probably want to do the same with the vaccine product extensions. And we'd want to say that when a Slot includes these extensions, they override whatever's present in the Schedule.

I'm inclined to move ahead with this on Monday, unless anyone has concerns?

Mr0grog commented 3 years ago

Sorry for not keeping up with this on Friday.

Say we have a slot X with 100 capacity that supports both 1st and 2nd doses. If I understand right you're saying:

Schedule A: Dose 1, holds Slot X1 with 100 capacity Schedule B: Dose 2, holds Slot X2 with 100 capacity

Ha, this is already wildly different from how I understood one should model this scenario! I think that explains my confusion. :)

So, in the above, I had thought you would model that as one schedule (assuming every slot really is either dose 1 or 2). It would have two dose extensions (since the spec says you MAY do that):

And in your more complex scenario:

Organization has a small Clinic lab that has 100 doses worth of a vaccine to offer for this week. They are confident they will have the supply to cover any number of dose 2 needs in 3 weeks, but they don't want to fully expose all 100 shots to be all dose 2, so they plan for 1-100 Dose up and would allow 10 new dose 2 to come in if needed. If they reach all their dose 2 values they will give 90 total dose 1.

This would be 100 Vaccine available with both dose 1 and 2 available.

I had thought you would model that as:

So after the reservations:

Now if we get 20 scheduled Dose 1s and 10 scheduled Dose 2s we would be looking at 70 remaining openings remaining for dose 1 with 30 total scheduled doses.

You’d have:

Now, that was just my understanding from reading the spec. Maybe I was getting it wrong.

jmandel commented 3 years ago

Both of the approaches seem possible as far as we've documented today. Clearly the approach @Mr0grog describes here is preferable to advertising the same capacity in 2 or 3 distinct places.

I think the question is whether we:

1) leave the underlying model as it is, and encourage publishers to avoid duplicating capacity across schedules (i.e., encourage publishers to define explicit for "dose 1 or dose 2" availability, as @Mr0grog describes above; we'd discourage publishers from representing the same appointment in more than one schedule to avoid the challenges that @jwjahns describes prior

2) update the underlying model to allow Slots to provide or override details from a Schedule, allowing Schedules to be less constrained (e.g., listing multiple doses or even just saying "we do COVID-19 vaccines" and nothing more); this way, Slots could fill in the details (e.g., "well the schedule doesn't mention doses, but this slot is for dose 1 only", or "well the schedule says dose 1 or dose 2, but this slot is dose 2 only")

Option (2) is more flexible over time by avoiding the need for combinatorial Schedules, but it leads to large Slot sizes and more complicated client logic (having to check for information in multiple places).

Mr0grog commented 3 years ago

Option (2) is more flexible over time by avoiding the need for combinatorial Schedules, but it leads to large Slot sizes and more complicated client logic

Agree on the more complicated logic part, but does it necessarily lead to coarser-grained slots? You could still have multiple slots with the same start/end time and different dose/product extensions, right?

(I hope I don't sound like I’m talking out of both sides of my mouth here. My first replies were overwrought and probably buried my opinion here, which is: insofar as it seems like we're imposing more complex client logic but not gaining anything other than slight implementer convenience, I’m slightly against — but that is not a strongly held opinion.)

jmandel commented 3 years ago

I realize what I said was ambiguous here: when I said it leads to larger slots I just meant over the wire, with more extensions the Slots will have more bytes. I don't think this is an actual problem -- and I was not suggesting that it would lead to less precise slots.

I also don't have a strong opinion here; the only thing I would really rather avoid is publishers overstating capacity, but there are ways to avoid this with either of the modeling choices above.

(Edit to fix dictation errors.)

Mr0grog commented 3 years ago

Ohhhhhhhh 😅 👍

jwjahns commented 3 years ago

Due to varying ways to build scheduling across organizations, I don't think we could quite fit @Mr0grog 's model. Actually being able to determine the amount of available dose 2's, for example, might be very performance-intensive depending on configuration.

If we were to say no to the Slot-level dose information, we would probably instead do something like:

Schedule A: dose 1+2 Mon: 100 capacity Tue: 100 capacity => 10 dose 2 appointments get scheduled on Monday; update to Schedule A1: dose 1 Mon: 90 capacity Schedule A2: dose 1+2 Tue: 100 capacity

Which is similar to putting the dose information on the Slot, but instead we're making new Schedules as needed when new dose combinations pop up.

Mr0grog commented 3 years ago

OK, am I understanding right that the issue here isn’t really so much where the dose info lives (on the schedule or on the slot) as that you’re specifically unable to talk about dose 2 appointments as something separate from dose 1?

In the scenario we’re describing, I was thinking the slot-level dose data you were asking for was to do something like:

On Monday:

On Tuesday, after scheduling 20 dose 1s and 10 dose 2s:

But it sounds like that wasn’t what you were getting at. Instead, is the problem that you don’t know about dose 1 ONLY as a separate slot from dose 1 & 2 at the start? So you want to do:

On Monday:

On Tuesday, after scheduling 20 dose 1s and 10 dose 2s:

Is that right?

Is the issue here that, in your system, or at least in the way people are using it, they just have a slot with X capacity and that advertises the different products/doses that could be available, and they change those products/doses as they get used up, rather than setting out their capacity for each combination ahead of time?

jwjahns commented 3 years ago

Yes, that second example is right - so compared to the model I gave above, the benefit of slot-level data would simply be that the Schedule resources remain consistent (instead of "splitting off" as availability changes).

Mr0grog commented 3 years ago

Got it. So I don’t think that changes my view, BUT I think I also get why this matters to you more than it does to me — in my data model, the only thing that really matches up to an object that’s represented in this spec is the location. I am always reprocessing and reformatting the schedules and slots, so I don’t keep track of the slot and schedule identifiers between requests to the SMART Scheduling Links API at all. I can imagine that having the schedule and slot IDs be [more] stable over time might be useful for other applications.

If I’m getting it right, that’s the real goal here: Schedule and Slot IDs that are stable over time in an environment where the doses (and products?) necessarily change based on factors that are not visible in the system (because users just aren’t putting them in that way, regardless of whether they could).

jwjahns commented 3 years ago

Yup, that's a good way of putting it! We can follow a Schedule-based approach as outlined above, it just might lead to strange behavior with the IDs and such if the API is used directly instead of being translated to another database.

Mr0grog commented 3 years ago

👍 I don’t have a very strong opinion here at all, then. My use case is made a tiny bit harder if we do this, but not much. @nickrobison-usds or other consumers might be taking more care with IDs than me; it’s possible this could be actively useful to them.

If we make this OK in the spec, I think it might be useful to recommend when (if ever?) to use schedule-level extensions rather than slot-level for dose & product.

@jwjahns one other thing I’m curious about here: do you encounter the same situation with product, or just dose?

jmandel commented 3 years ago

I'm not entirely following @jwjahns and @cooperthompson. I think the crux is:

Actually being able to determine the amount of available dose 2's, for example, might be very performance-intensive depending on configuration.

Such that in your example when you write:

Schedule A: dose 1+2
Mon: 100 capacity
Tue: 100 capacity

... what this really means is "at most 100 capacity for flexible slots that work for either dose 1 or dose 2" -- and indeed it seems like by the end of Monday you've discovered that the capacity was in fact no more than 10, and not 100 after all? (I say this because it appears that booking 10 slots led to 0 availability of dose 2 appointments.) If that's the case, why ever assign 100 slots to a "dose 1 or dose 2" schedule in the first place? I'm having trouble understanding what you know directly, and what you know as upper or lower bounds.

Also in your example, when you write "A2", this appears to be the same as "A", so I'm not sure why a new schedule would be created.

In general you can creates schedules for "Dose 1", "Dose 2", and "Dose 1 or Dose 2" and manage only three schedules. (Or we can push down these descriptions into Slots and just have a generic COVID Vaccination Schedule -- but either way, my questions above remain.)

It seems like our modeling choices aren't directly causing the issue here; rather, the challenge seems to be stemming from a lack of ability to determine "amount of available dose 2's".

jmandel commented 3 years ago

If it's helpful to talk through this directly, I'm happy to schedule a time to talk -- ping me on https://chat.fhir.org/#narrow/stream/281612-smart.2Fscheduling-links