Skip to content

Dead beds — developer reference

Audience: engineers working on Booking/BookingWizard/Step2 - Availability check, XtremeAvailability/MF/InUse, BookingMasterData/RARA/DeadBeds, or anything that decides whether a room selection may be booked.

Source of truth: the Mendix model, read via model/ and db/model.db. Microflow names, node numbers, expressions and message strings are verbatim from commit 80b58aeb8, Mendix 10.24.21. Node numbers in [n] match python3 tools/mxrender.py <flow> and the steps table.

Written against 83d87ba8e and re-derived against 80b58aeb8 - 61 Mendix commits later, the same day. The wizard path is byte-identical. The Xtreme path was refactored underneath this document while it was being written: §4 is rewritten rather than adjusted, and the two behaviours the refactor introduced are D10 and D11.

Anything the model does not state is marked (inferred) and should be confirmed with the team. Where a name is misspelled in the model it is reproduced misspelled — DeadbedsOverrridden has three rs, and code that reads it must too.


1. What a dead bed is

(inferred — no annotation in the model defines the term.) A bed that a booking leaves unsellable. Camp availability dips and recovers around a stay; if the dip strands a bed that nobody can now book, that bed is dead. Wilderness cares because a stranded bed is lost revenue at a camp that is otherwise nearly full.

The model measures it as a count per room type_Double, Family, Honeymoon, Twin — and separately at the beginning and the end of the stay. Nothing stores a monetary value; the money appears only inside warning text (§6).

Two distinct implementations compute the same arithmetic against two different availability sources, which is the single most important fact in this document:

Path Availability read Duplicate guard Writes a log Used by
Booking wizardBooking.DeadBedCheck_Begin_X / _End_X WishAPI.LodgeAvailability / RoomsAvailableAfterWait yes, returns 99 yes, Logging.DeadBed_log room selection in step 2
Xtreme availabilityBooking.XAvail_DeadBedCheck_Begin / Booking.XAvailDeadBedCheck_End tmpXAVailRoomTypeAvailabilityDetail / RoomAvailAfterWait no no availability screens, trip finder

2. The arithmetic

Booking.DeadBedCheck_Begin_X($RoomsRequired, $RoomType, $Check, $LodgeAvailabilityList, $Booking, $DeadBed_log) : Integer

Guarded by $Check at [2]: with false, the flow returns 0 — see §4 for who sets it.

It filters the availability list to one room type [4], sorts by DateUse ascending [5], counts [6], and then reads exactly three days by loop counter [18-32]:

Counter Variable Meaning
1 $BedsTwoDaysBefore two days before the stay starts
2 $BedsOneDayBefore the day before
3 $Beds_Start the first day of the stay

Each is RoomsAvailableAfterWait — availability after waitlisted demand, not raw availability.

Two conditions then decide the answer, verbatim:

[34]  pre-existing:  $BedsTwoDaysBefore < $BedsOneDayBefore
                 and $BedsOneDayBefore > $Beds_Start
                 and $BedsTwoDaysBefore + $Beds_Start < $BedsOneDayBefore

[33]  after booking: $BedsTwoDaysBefore < $BedsOneDayBefore
                 and $BedsOneDayBefore > ($Beds_Start - $RoomsRequired)
                 and $BedsTwoDaysBefore + $Beds_Start - $RoomsRequired < $BedsOneDayBefore

The shape is "the day before is a local peak, and the two neighbours together cannot absorb it". [33] asks it of the world with this booking taken, [34] of the world without.

[33] [34] Returned Node
false 0 [43]
true false $BedsOneDayBefore - ($BedsTwoDaysBefore + $Beds_Start - $RoomsRequired) — the whole post-booking count [42]
true true $DeadBead_PostBook - $DeadBed_PreBook if positive, else 0 [39], [40]

So the number is incremental only when dead beds already existed. If the stay creates the condition from nothing, the full post-booking count is returned. $DeadBead_PostBook is spelled that way in the model [36].

Booking.DeadBedCheck_End_X mirrors it at the other end — counters 1/2/3 are $Beds_End, $Beds_OneDayAfter, $Beds_TwoDaysAfter [13-25], conditions at [26] and [27], returns at [32], [35], [36]. Note the loop order: the list is still sorted ascending, so counter 1 is the last day of the stay, and TwoDaysAfter is the third row.

99 means "could not check"

Both flows count the filtered availability rows and bail if there are more than three ([7] in each). That branch logs Logging.LoggingSeverity.Critical "Duplicate availability records could not check for deadbeds at the beginning of your booking …", shows the user the same text as a warning, and returns 99 — Begin [11-13], End [37-42].

Nothing downstream distinguishes 99 from a real count: every consumer tests > 0 (§3, §5). A camp with duplicate availability rows therefore reads as 99 dead beds per room type, blocks the booking, and mails the managers a price for 99 beds. (inferred: unintended — the log severity says the author treated it as a fault, not as a verdict.)

3. The wizard orchestrator — Booking.CheckForDeadBeds_X (85 steps)

Returns Boolean: true means "dead beds were created". Five gates before any arithmetic:

Gate Node Condition
booking method [2] $AvailableRoomConfig/BookingMethod = Booking.BookingMethod.Wish
availability [3] status is neither Available nor No_Private_Vehicle
lead time [4] $TravelLocation/SeqStartDate > addWeeksUTC([%CurrentDateTime%], 8)
season, start [15] a BookingMasterData.DeadBedMonths row for this supplier covers SeqStartDate$CheckDeadsBegin = true [82]
season, end [18] same for SeqEndDate$CheckDeadsEnd = true [81]
neither [21] $CheckDeadsBegin or $CheckDeadsEnd false → return false [22]

Inside eight weeks of travel, nothing is checked at all. (inferred: by then the beds are a sunk problem, so the check exists to protect future inventory.)

It then calls Booking.CallForLodgeAvailability_Overall for the stay ±2 days [26], zeroes all eight counters plus DeadBedsCreatedWhenNotAllowed [42], and per room type — Twin [64-67], Honeymoon [68-71], Double [72-75], Family [76-79] — creates a Logging.DeadBed_log, calls Begin and End, and stores both integers on Booking.AvailableRoomConfig.

The verdict [61]:

( (DeadBedsCreatedBegin_Double>0 or …_Fam>0 or …_Hm>0 or …_Twin>0) and $CheckDeadsBegin
  or (DeadBedsCreatedEnd_Double>0 or …_Fam>0 or …_Hm>0 or …_Twin>0) and $CheckDeadsEnd )

Housekeeping rides along: logs older than a month are retrieved [6] and deleted [60], so Logging.DeadBed_log keeps roughly 30 days.

The flow that finds dead beds does not record the verdict

CheckForDeadBeds_X writes DeadBedsCreatedWhenNotAllowed = false at [42] and never writes true. The flag is set by its two callers, from the Boolean it returns — which means the consequence of a dead bed depends on which caller asked:

Caller On true On false
Booking.CheckRoomSelection [146-151] flag true [148], $Status = XtremeAvailability.AvailabilityStatus.Dead_bed_warning [149], information "Your room selection will be waitlisted" [151] flag false [150]
Booking.UpdateAvailabilityStatusForAccom_X [98-101] flag true together with a recomputed BookThis [101], after downgrading $AvailabilityStatus [100] DeadBedsCreated and the flag both false [119]

The excluded predecessor Booking.CheckForDeadBeds did set the flag itself, with the availability status folded into the expression at [59], so this is a deliberate move of the decision to the callers rather than an omission (inferred).

One consequence is easy to miss: in UpdateAvailabilityStatusForAccom_X, a status of Dead_bed_warning with $SearchSimilarCamps false runs Booking.TripSuggest as the current user, through CommunityCommons.executeMicroflowAsUser_1 [111-114]. A dead bed therefore triggers an alternative-camp suggestion, not only a refusal.

4. The Xtreme path, and a flag that is wired to the wrong variable

XtremeAvailability.XAvail_CheckForDeadbeds_Overall (59 steps) loops the selected locations and calls XtremeAvailability.XAvailCheckDeadBeds_supplier per accommodation code [23], [40], then writes the accumulated string to Availability.UserBookingAvailConfig.DeadBedWarning [47].

The supplier sweep (51 steps) applies the same eight-week guard [3], the Wish booking method [4] and the DeadBedMonths window [15-21], then calls the shared per-room-type flow XtremeAvailability.GetDeadBedPerRoomtype three times - Family [33], Double+Twin [37], Honeymoon [41] - and joins the returned phrases into $Warning, prefixed with the supplier name [47].

XtremeAvailability.GetDeadBedPerRoomtype (23 steps) filters the availability list to the room type [5], [9], calls Booking.XAvail_DeadBedCheck_Begin [6] and Booking.XAvailDeadBedCheck_End [10], and builds "Deadbeds created at beginning of stay :" [19] and "Deadbeds created at end of stay :" [18].

Defect D1 - the end-of-stay check is still gated by the beginning-of-stay flag. It survived the refactor and now sits in two places. The sweep passes $CheckDeadsBegin at all three call sites [33], [37], [41], and inside the shared flow the End call receives that same parameter [10]:

[10] CALL Booking.XAvailDeadBedCheck_End($RoomsRequired, $RoomType, $CheckDeadsBegin, ...)

$CheckDeadsEnd is declared [14], set [48], read once in the guard [21], and passed to nothing. The wizard path still gets this right - Booking.CheckForDeadBeds_X [66], [70], [74], [78] all pass $CheckDeadsEnd. Consequence unchanged: on the availability screens a stay whose end falls in a dead-bed month but whose start does not is not checked at the end, and one whose start is in a dead-bed month is checked at the end whether or not the end month is configured.

Defect D10 - double and twin are checked as one room type. The refactor merged them: the guard is RoomCountDouble > 0 or RoomCountTwin > 0 [36] and the call passes RoomCountDouble + RoomCountTwin rooms with room type Booking.RoomType.Twin [37]. Doubles are counted against twin availability, and RoomType._Double is no longer used on this path at all - while the wizard path still checks four types separately. Whether that is a simplification or a mistake needs the team (inferred); either way the two paths now disagree about what a room type is.

Defect D11 - every beginning-of-stay phrase says "twin". The end-of-stay text uses getCaption($RoomType) [21], but the beginning-of-stay text hard-codes the words [23], so a family or honeymoon dead bed at the start of a stay is reported to the consultant as "2 twin room(s)".

XtremeAvailability.XAvailCheckDeadBeds_supplier_2 also exists, calls the shared flow four times, and is excluded from deployment with no callers - listed in §10.

5. What a dead bed does to a booking

Booking.CanBook is the gate, called from Booking.IVK_SelectRooms_040625, Booking.Sub_BookProvisionally_AllInventory (and _hold), Dashboard.IVK_WishStatusToProvOverrideWait_CloseForm and DataManagement.WishBookingLine_Update:

[14] SPLIT if $AvailableRoomConfig/DeadBedsCreatedWhenNotAllowed
[15]   SPLIT if $AvailableRoomConfig/DeadbedsOverrridden        (three r's)
[16]     MESSAGE information "As the booking {1} is creating deadbed(s) and occupancy at this
         time is very high, this can only be booked by a Wilderness Manager. It will however be
         waitlisted in the meantime."
[17]     CHANGE $BookingLine set { DeadBedsOverridden = false; BookingLine_Account_DeadOverride = empty }
[19]   END return false

Not an error and not a hard stop on the itinerary: the line is refused here and waitlisted instead. [17] also clears any previous line-level override, so an override does not survive a re-check — it must be granted against the current room configuration.

The override

Dashboard.IVK_OverrideDeadbeds, on Dashboard.BookingLine_Accomm_Edit and its popup (actionButton8):

  1. AvailableRoomConfig.DeadbedsOverrridden = true, OverrideBy = $currentUser [2]
  2. Booking.LogEvent(… 'Deadbeds overridden by manager on this booking line', Object_Type.BookingLine) [4]
  3. Booking.SendDeadBedsEmail($BookingLine, $Account, $AvailableRoomConfig) [6]
  4. BookingLine.DeadBedsOverridden = true, BookingLine_Account_DeadOverride = $Account [7]

Two flags, two levels: the config-level one unblocks CanBook, the line-level one records who approved it. Booking.CanBook is the only other live writer, and it writes false [17] — to the line-level flag.

Defect D8 — the configuration-level override is never withdrawn. Across the whole live model, AvailableRoomConfig.DeadbedsOverrridden has exactly one writer, Dashboard.IVK_OverrideDeadbeds, and it writes true. Nothing sets it back to false. So once a room configuration has been overridden, CanBook [15] passes it for the life of that record, however the selection changes afterwards — while the line-level flag is cleared on every re-check [17]. Verified by listing every writer of both attributes.

Restriction to a manager is not in the microflow — it says "can only be booked by a Wilderness Manager" but performs no role check. Whether the button is limited is page security, and Dashboard.BookingLine_Accomm_Edit is the place to confirm it (inferred).

6. The two messages, and what they cost

Booking.CheckDeadBedsForWarning (27 steps, called from Booking.CheckRoomSelection, Booking.Sub_Select_AvailableRoomConfig and the GridConfigureARC_XAVail pair) builds the consultant-facing sentence. Guarded on DeadBedsCreatedWhenNotAllowed [2], it appends per-room-type phrases [25-26], then prices them:

[13] CALL Pricing.GetRackPrice($Booking, $Supplier, $Option, $TravelLocation/SeqStartDate)
[15] $Price = if $TourplanPricing = empty then 0 else round($TourplanPricing/Gs_Ad_Tw * $DeadBeds)
[17] $FrancisWeirdDenom = $RoomsBooked + $DeadBeds
[18] $DeadBedPerc = round($DeadBeds div $FrancisWeirdDenom, 2) * 100

$FrancisWeirdDenom is the variable's real name, in both this flow and Booking.SendDeadBedsEmail [11]. A person's name in a production expression is worth removing.

The message is now stored as well as logged: AvailableRoomConfig.DeadBedWarning = $Message [21], a String attribute added in this revision whose only writer this is. A page can show the warning without recomputing it - and a stale sentence can outlive the counters that produced it, because nothing clears it (§7).

The result is logged at Warning severity [23] under the fixed label 'Dead bed warning as follows :', with different wording when $Booking/API_System = API.API_System.ITRVL: the partner channel gets the occupancy explanation and a bulleted list of options - another room type, an alternate camp, or swapping camps around.

Booking.SendDeadBedsEmail sends the same numbers by mail via AdvEmail.SendEmailMessage_msg('Dead beds created booking: … camp : …') [15], and Dashboard.IVK_DeadBed_ClearanceEmail addresses the branch's reservations and operations managers, resolved through Agency.BranchDepartment_EmployeeResMgr and _EmployeeOpsMgr [5-6].

7. Configuration and state

Where What
BookingMasterData.DeadBedMonths StartDate, EndDate, Display, Seq, associated to a supplier. Rows switch the check on for a date range. Maintained on BookingMasterData.DeadBedConfig / DeadBedMonths_View; Och_DeadBedMonth_Commit is a two-step commit [2]
Booking.AvailableRoomConfig 13 attributes: eight DeadBedsCreated{Begin,End}_{Double,Fam,Hm,Twin} counters, DeadBedsCreated, DeadBedsCreatedWhenNotAllowed, DeadbedsOverrridden, PotentialDeadBeds{Begin,End}_taken
Booking.BookingLine DeadBedsOverridden plus BookingLine_Account_DeadOverride
Logging.DeadBed_log the three-day window that produced a verdict: TwoDaysBefore{Date,Amt}, DayOneBefore{Date,Amt}, DayStart{Date,Amt}, DayEnd{Date,Amt}, OneDayAfter{Date,Amt}, TwoDaysAfter{Date,Amt}, RoomTypeBegin, RoomsRequired, Booking. Retained ~30 days (§3)
Availability.UserBookingAvailConfig.DeadBedWarning the Xtreme screens' warning string, written by XtremeAvailability.XAvail_CheckForDeadbeds_Overall [47]; cleared by XtremeAvailability.XAVail_ClearBookingSuggestions
Booking.AvailableRoomConfig.DeadBedWarning new in 80b58aeb8: the wizard's warning sentence, stored as well as logged. One writer, Booking.CheckDeadBedsForWarning [21], and no clearer - unlike the counters beside it
Administration.Account.ShowPotentialDeadbeds per-user toggle (inferred: shows the potential-dead-bed columns on availability screens)
Pricing.TakingUpPotentialDeadBeds one attribute, DiscountPercentage — a discount for a booking that takes up beds that would otherwise die (inferred). Maintained from BookingMasterData.Pricing_Overview; a second grid page is named Taking_Potential_DB_not_in_use

Booking.AvailableRoomConfig.DeadBedsCreatedWhenNotAllowed has eight live writers and 24 live write sites, and only two of those sites write true (§3). Everything else clears it:

Flow Sites Meaning
Booking.SetRoomConfigString 15, all false rebuilding the room-configuration string clears the verdict
Booking.UpdateAvailabilityStatusForAccom_X [11], [18], [119] false; [101] true refreshing availability re-decides it
Booking.CheckRoomSelection [148] true, [150] false as above
Booking.ShowAvailableRooms_InitialSelect, Booking.IVK_ShowAvailableRooms_Reselect one each, false opening or reopening room selection clears it
Booking.CheckForDeadBeds_X [42] false zeroes before measuring
Maintenance.ProcessExpiredLine, Maintenance.ProcessExpiredLine_testprocess one each, false a held line expiring clears it

The verdict is transient. It reflects the last availability calculation, not the history of the booking, and any refresh — including one triggered from a partner API call — clears it. That is why coverage.py reports 74 entry points reaching a mutator of this attribute (§11): almost all of them reach it by resetting it as a side effect of ordinary availability work.

8. Entry points — buttons only

entry_points knows 11, all button. No published REST operation, no scheduled event, no commit hook anywhere in the dead-bed area.

Flow Page / widget
Booking.Sub_Select_AvailableRoomConfig Booking.SNP_Step2Form and Booking.SNP_Step2Form_300426, triggers 49, 54, 55
Dashboard.IVK_OverrideDeadbeds Dashboard.BookingLine_Accomm_Edit, Dashboard.BookingLine_Accomm_Edit_Popup, actionButton8
XtremeAvailability.IVK_XAvailCheckforDeadBeds XtremeAvailability.AllAvailability, XtremeAvailability.W_Availability, XtremeAvailability.Availability_Check_Member, actionButton2

Nothing runs dead-bed logic in the background. If the availability screens are never opened and the wizard never reaches room selection, no dead bed is ever counted.

Four more buttons reach dead-bed state without being about dead beds, and they matter because each one can change or clear a verdict (§7):

Flow Page / widget Why it touches dead beds
Booking.ShowAvailableRooms_InitialSelect Booking.SNP_Step2Form_300426 / actionButton88 clears the counters when room selection opens
Booking.IVK_ShowAvailableRooms_Reselect Dashboard.BookingLine_Accomm_Edit_Agent / actionButton3 clears them again on reselect, from the agent-facing edit screen
Dashboard.IVK_WishStatusToProvOverrideWait_CloseForm DataManagement.BookingLineMaintenance / actionButton59 goes through Booking.CanBook, so it can be refused for dead beds
Dashboard.IVK_DeadBed_ClearanceEmail Booking.Sn_BookingFile_BookingLine / microflowTrigger6 asks the branch managers for clearance, from the booking file

Maintenance.ProcessExpiredLine_testprocess also clears the counters and is live, reachable from Administration.Database_Debug_Dashboard / actionButton182. It is a debug twin of Maintenance.ProcessExpiredLine and is treated as out of scope in journeys/dead-beds.toml — a debug dashboard is not a journey entry point, but it is a way to change dead-bed state in a real environment, which is worth knowing before diagnosing one.

The same button exists on page copies

Every page above has duplicates, and the duplicates carry the same widgets, so "fixed on the page" and "fixed everywhere" are different statements. The full set, from entry_points:

Flow Every page that triggers it
Booking.ShowAvailableRooms_InitialSelect Booking.SNP_Step2Form (actionButton88, microflowTrigger51), Booking.SNP_Step2Form_300426 (both again), Booking.TravelLocationAltCamps / image8
Booking.IVK_ShowAvailableRooms_Reselect Dashboard.BookingLine_Accomm_Edit, Dashboard.BookingLine_Accomm_Edit_Agent, Dashboard.BookingLine_Accomm_Edit_Popup, all actionButton3
Dashboard.IVK_DeadBed_ClearanceEmail Booking.Sn_BookingFile_BookingLine (microflowTrigger6, microflowTrigger7), Booking.Sn_BookingFile_BookingLine_View / microflowTrigger6
Dashboard.IVK_WishStatusToProvOverrideWait_CloseForm DataManagement.BookingLineMaintenance / actionButton59, DataManagement.BookingLineMaintenance_230226 / microflowTrigger5
Maintenance.ProcessExpiredLine_testprocess Administration.Database_Debug_Dashboard, Administration.Database_Debug_Dashboard_Merge, Administration.Database_Debug_Dashboard_MergeConflict_05_09_2025, all actionButton182

Booking.TravelLocationAltCamps is the alternative-camps page, which closes a loop with §3: a dead bed sends the consultant to alternative camps, and picking one from there re-enters room selection and clears the verdict.

The last row is worth a note of its own: a page named after a merge conflict is deployed and has a working button on it (inferred: an accident of a Studio Pro merge, not a decision).

9. Defects and traps

ID What Where
D1 End-of-stay checks gated by $CheckDeadsBegin on the Xtreme path; $CheckDeadsEnd never passed XAvailCheckDeadBeds_supplier [136], [162], [174], [187]
D2 99 is a sentinel for "could not check" and every consumer treats it as a count DeadBedCheck_Begin_X [13], _End_X [42], consumers [61]
D3 DeadbedsOverrridden (three rs) and DeadBedsOverridden (line level) differ by spelling, not by meaning-at-a-glance AvailableRoomConfig, BookingLine
D4 $FrancisWeirdDenom — a person's name in a production expression, in two flows CheckDeadBedsForWarning [17], SendDeadBedsEmail [11]
D5 "can only be booked by a Wilderness Manager" is asserted in a message but enforced nowhere in the logic Booking.CanBook [16]
D6 The Xtreme variants have no duplicate-availability guard, so a duplicated row silently skews the count instead of returning 99 XAvail_DeadBedCheck_Begin [7-18]
D7 Four dead-bed flows are excluded from deployment but still in the model, two of them near-duplicates of live ones (CheckForDeadBeds, CheckDeadBedsForWarning_20241113) see §10
D8 The configuration-level override is set true once and never cleared, while the line-level one is cleared on every re-check IVK_OverrideDeadbeds [2] vs CanBook [17]
D9 The verdict flag is cleared by 22 of its 24 live write sites, several of them reachable from published REST operations, so a dead-bed refusal can be erased by an unrelated availability refresh §7
D10 On the Xtreme path double and twin are now one room type: RoomCountDouble + RoomCountTwin rooms checked as RoomType.Twin, while the wizard still checks four types XAvailCheckDeadBeds_supplier [36], [37]
D11 Every beginning-of-stay phrase hard-codes "twin room(s)"; the end-of-stay phrase uses getCaption($RoomType) GetDeadBedPerRoomtype [21] vs [23]
D12 Booking.AvailableRoomConfig.DeadBedWarning is written once and never cleared, so the stored sentence can outlive the counters it describes CheckDeadBedsForWarning [21]

10. What this document does not cover

Five dead-bed documents are unreachable from the roots in journeys/dead-beds.toml, and that is the whole of the unreachable set:

Document Status Why not covered
DataManagement.jaGetWISHDeadBeds live, 0 callers A Java action nothing invokes. source/ holds the body; whether it is dead code or called dynamically needs the check in when to read the code
Booking.CheckForDeadBeds excluded Predecessor of _X, 80 steps
Booking.CheckDeadBedsForWarning_20241113 excluded Dated copy, 29 steps
Booking.CheckDeadBedsForBookingLeg excluded Trip-search variant, 11 steps
BookingTemplates.CheckForDeadBeds_trips_XAvail excluded Template variant, 76 steps
XtremeAvailability.XAvailCheckDeadBeds_supplier_2 excluded, 0 callers New in 80b58aeb8: a second supplier sweep calling XtremeAvailability.GetDeadBedPerRoomtype four times rather than three - the un-merged room types of D10. Work in progress (inferred)

Also deliberately out of scope: the availability engine that produces RoomsAvailableAfterWait and RoomAvailAfterWait (dead beds only read it), waitlisting mechanics beyond the fact that a refused line is waitlisted, Pricing.GetRackPrice internals, and BookingTemplates.CheckForDeadBeds_trips — live, called twice, and the template journey's subject rather than this one.

11. Reproducing this analysis

python3 tools/scope.py Booking XtremeAvailability BookingTemplates Dashboard BookingMasterData \
        --roots Booking.Sub_Select_AvailableRoomConfig Booking.CanBook \
                XtremeAvailability.IVK_XAvailCheckforDeadBeds --all
python3 tools/coverage.py Booking.AvailableRoomConfig \
        --attr DeadBedsCreatedWhenNotAllowed,DeadbedsOverrridden --ui docs/deep-dives/dead-beds.md
python3 tools/verify.py docs/deep-dives/dead-beds.md

coverage.py on this subject reports 74 of 76 entry points unknown, and that number is expected rather than a to-do list. The attribute it measures is reset by ordinary availability work (§7), so the reachable set is "everything that can refresh availability" — sixteen published REST operations among them. The two it reports as documented, Booking.Sub_Select_AvailableRoomConfig and Dashboard.IVK_OverrideDeadbeds, are the only two that reach the attribute because of dead beds. Measured per journey, the honest question is the one scope.py --roots answers, in §10.

Every number here came from db/model.db through the MCP endpoint. The two that are worth re-running after any extract, because they are the ones that move:

-- D1: is the end check still wired to the begin flag?
select node, text from steps
where doc = 'XtremeAvailability.XAvailCheckDeadBeds_supplier'
  and (text like '%CheckDeadsBegin%' or text like '%CheckDeadsEnd%') order by node;

-- the unreachable set in §10
select name, excluded from docs where lower(name) like '%deadbed%' and kind = 'Microflow';