@curless/hotel-storefront 0.54.0 → 0.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/dist/backend.d.ts +9 -0
  2. package/dist/backend.d.ts.map +1 -1
  3. package/dist/backend.js.map +1 -1
  4. package/dist/card.generated.d.ts +1 -1
  5. package/dist/card.generated.js +2 -2
  6. package/dist/card.generated.js.map +1 -1
  7. package/dist/config.d.ts +33 -2
  8. package/dist/config.d.ts.map +1 -1
  9. package/dist/config.js.map +1 -1
  10. package/dist/demo-hotels.d.ts.map +1 -1
  11. package/dist/demo-hotels.js +29 -13
  12. package/dist/demo-hotels.js.map +1 -1
  13. package/dist/fence.d.ts.map +1 -1
  14. package/dist/fence.js +4 -3
  15. package/dist/fence.js.map +1 -1
  16. package/dist/huazhu/backend.d.ts.map +1 -1
  17. package/dist/huazhu/backend.js +17 -22
  18. package/dist/huazhu/backend.js.map +1 -1
  19. package/dist/huazhu/catalog.d.ts +6 -6
  20. package/dist/huazhu/catalog.d.ts.map +1 -1
  21. package/dist/huazhu/catalog.js +6 -9
  22. package/dist/huazhu/catalog.js.map +1 -1
  23. package/dist/legal.d.ts.map +1 -1
  24. package/dist/legal.js +104 -80
  25. package/dist/legal.js.map +1 -1
  26. package/dist/lib.d.ts +1 -1
  27. package/dist/lib.d.ts.map +1 -1
  28. package/dist/lib.js +1 -1
  29. package/dist/lib.js.map +1 -1
  30. package/dist/otaless/backend.d.ts +31 -0
  31. package/dist/otaless/backend.d.ts.map +1 -0
  32. package/dist/otaless/backend.js +502 -0
  33. package/dist/otaless/backend.js.map +1 -0
  34. package/dist/otaless/client.d.ts +103 -0
  35. package/dist/otaless/client.d.ts.map +1 -0
  36. package/dist/otaless/client.js +110 -0
  37. package/dist/otaless/client.js.map +1 -0
  38. package/dist/otaless/fake.d.ts +27 -0
  39. package/dist/otaless/fake.d.ts.map +1 -0
  40. package/dist/otaless/fake.js +239 -0
  41. package/dist/otaless/fake.js.map +1 -0
  42. package/dist/otaless/make.d.ts +4 -0
  43. package/dist/otaless/make.d.ts.map +1 -0
  44. package/dist/otaless/make.js +71 -0
  45. package/dist/otaless/make.js.map +1 -0
  46. package/dist/paid.d.ts.map +1 -1
  47. package/dist/paid.js +9 -11
  48. package/dist/paid.js.map +1 -1
  49. package/dist/present.d.ts +6 -1
  50. package/dist/present.d.ts.map +1 -1
  51. package/dist/present.js +20 -5
  52. package/dist/present.js.map +1 -1
  53. package/dist/reference.d.ts.map +1 -1
  54. package/dist/reference.js +10 -10
  55. package/dist/reference.js.map +1 -1
  56. package/dist/server.d.ts +2 -2
  57. package/dist/server.d.ts.map +1 -1
  58. package/dist/server.js +6 -4
  59. package/dist/server.js.map +1 -1
  60. package/dist/supplier.d.ts.map +1 -1
  61. package/dist/supplier.js +3 -0
  62. package/dist/supplier.js.map +1 -1
  63. package/dist/surface.d.ts.map +1 -1
  64. package/dist/surface.js +86 -66
  65. package/dist/surface.js.map +1 -1
  66. package/dist/tools.d.ts +8 -0
  67. package/dist/tools.d.ts.map +1 -1
  68. package/dist/tools.js +152 -109
  69. package/dist/tools.js.map +1 -1
  70. package/dist/types.d.ts +35 -0
  71. package/dist/types.d.ts.map +1 -1
  72. package/dist/vocab.d.ts +0 -28
  73. package/dist/vocab.d.ts.map +1 -1
  74. package/dist/vocab.js +19 -46
  75. package/dist/vocab.js.map +1 -1
  76. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
package/dist/tools.js CHANGED
@@ -14,7 +14,7 @@ import { regionOf } from './regions.js';
14
14
  import { activeKeysOf, byRoomType, facetsOf, keyWords, matchesTerms, optionsOf, roomTermsOf, termWords, } from './room-filters.js';
15
15
  import { SAME_BOOKING_MS } from './same-booking.js';
16
16
  import { MAX_EXTRA_QUANTITY, MAX_ROOMS_PER_LINE, clampCount, pickedKey, shownOf, stampOf, tripKey, } from './trip.js';
17
- import { DEMO_NOTE, branded, catalogue, noteFor, upFirst } from './vocab.js';
17
+ import { branded, catalogue, upFirst } from './vocab.js';
18
18
  // The eleven things a guest can do: find hotels, look at one on dates, see what
19
19
  // else it offers, build a trip, ask for the rooms, and deal with a booking they
20
20
  // already have.
@@ -145,7 +145,29 @@ export const withheldTools = (n, caps) => new Set([
145
145
  ...(caps.changes || caps.extras ? [] : [n.previewChange, n.changeBooking]),
146
146
  ...(caps.policies === false ? [n.policies] : []),
147
147
  ...(caps.unionpay ? [] : [n.payWithUnionPay]),
148
+ // Nothing can be booked here yet (`readOnly`, Otaless 2026-11-03): no tool
149
+ // that books, finds, changes or cancels a booking - the card's own two
150
+ // for Reserve included, so no button that books is drawn.
151
+ ...(caps.readOnly
152
+ ? [
153
+ n.requestBooking,
154
+ n.pickRoom,
155
+ n.bookPicked,
156
+ n.listBookings,
157
+ n.previewCancellation,
158
+ n.cancelBooking,
159
+ n.previewChange,
160
+ n.changeBooking,
161
+ n.payWithUnionPay,
162
+ ]
163
+ : []),
148
164
  ]);
165
+ /**
166
+ * What to tell a guest who wants to book where nothing can be booked yet
167
+ * (`capabilities.readOnly`) - the same words in the instructions and in each
168
+ * answer that would otherwise say how to book.
169
+ */
170
+ export const readOnlyWords = (v) => `Nothing can be booked through ${v.brand} yet: it shows ${v.noun}s, rooms and prices only. When the guest wants to book, say so plainly - nothing is booked or held - and suggest booking with the ${v.noun}'s own group directly, on its website or app, with the ${v.noun}, room and dates from here.`;
149
171
  const forCapabilities = (tools, n, v, caps) => {
150
172
  const withheld = withheldTools(n, caps);
151
173
  const without = (schema, ...keys) => {
@@ -296,18 +318,16 @@ const forCapabilities = (tools, n, v, caps) => {
296
318
  if (t.name === n.requestBooking && caps.booking === 'pay-at-hotel' && !v.market) {
297
319
  out = {
298
320
  ...out,
299
- // ⚠️ A SANDBOX BOOKS NOTHING REAL, and its description says so
300
- // itself: the instructions carried "test environment" while this
301
- // line still promised "the hotel's own reservation" (2026-09-30).
302
- description: v.test
303
- ? `Makes a test booking in ${v.brand}'s own test system, for testing: each stay gets its own confirmation code there, and none of it holds a room for anyone or is a stay anyone goes to. ${caps.prepaid
304
- ? 'A rate marked paid in advance is booked on its own, and not at once: the answer gives a card page in test mode and the time it is paid by, and the stay is booked once it is paid - no card is collected here. Every other rate is paid by nobody.'
321
+ // ⚠️ A BOOKING THAT IS NOT A RESERVATION SAYS SO ITSELF (2026-09-30: the
322
+ // description promised "the hotel's own reservation" on the sandbox) -
323
+ // as the fact, never "test" or "simulated" (robin, 2026-11-03).
324
+ description: v.test || v.demo
325
+ ? `Books the trip's rooms for a named guest: each stay gets its own confirmation code, and ${v.test
326
+ ? 'none of it holds a room for anyone or is a stay anyone goes to'
327
+ : `none of it is sent to ${v.brand} or holds a real room`}. ${caps.prepaid
328
+ ? 'A rate marked paid in advance is booked on its own, and not at once: the answer gives a card page where no real money moves and the time it is paid by, and the stay is booked once it is paid - no card is collected here. Every other rate is paid by nobody.'
305
329
  : 'No payment is taken and no card is collected.'} All of the trip is booked or none of it. Preferences - a bed type, a floor, a late arrival - ride along on the booking as requests.`
306
- : v.sandbox
307
- ? `Makes a simulated booking in a simulated copy of ${v.brand}'s booking system: each stay gets its own confirmation code there, and none of it is a ${v.brand} reservation or holds a real room. ${caps.prepaid
308
- ? 'A rate marked paid in advance is booked on its own, and not at once: the answer gives a card page where no real money moves and the time it is paid by, and the stay is booked once it is paid - no card is collected here. Every other rate is paid by nobody.'
309
- : 'No payment is taken and no card is collected.'} All of the trip is booked or none of it. Preferences - a bed type, a floor, a late arrival - ride along on the booking as requests.`
310
- : `Books the trip's rooms with ${v.brand} for a named guest: each stay becomes the hotel's own reservation, with its own confirmation code, paid at the hotel. No payment is taken here and no card is collected. All of the trip is booked or none of it. Preferences - a bed type, a floor, a late arrival - ride along on the booking as requests the desk tries to meet.`,
330
+ : `Books the trip's rooms with ${v.brand} for a named guest: each stay becomes the hotel's own reservation, with its own confirmation code, paid at the hotel. No payment is taken here and no card is collected. All of the trip is booked or none of it. Preferences - a bed type, a floor, a late arrival - ride along on the booking as requests the desk tries to meet.`,
311
331
  };
312
332
  }
313
333
  }
@@ -596,10 +616,10 @@ const allTools = (n, v) => {
596
616
  ? // ⚠️ THE GROUP HOLDS THE BOOKING, NOT THE MARKET - and what a booking
597
617
  // makes is the group's: a hold, a booking that holds no room, or a
598
618
  // reservation paid at the hotel. The answer says which, stay by stay.
599
- // ⚠️ NO "DEMONSTRATION" / "TEST" / "SIMULATED" IN A MARKET (robin, 2026-11-03).
619
+ // ⚠️ NO "DEMONSTRATION" / "TEST" / "SIMULATED" (robin, 2026-11-03).
600
620
  `Books the trip's rooms for a named guest with the hotel group each stay belongs to, one group at a time: a trip holding two groups' hotels is booked group by group. What a booking makes is that group's - a hold that lapses on its own and is not sent to the group, a booking that holds no room for anyone, or the hotel's own reservation paid at the hotel - and the answer says which for every stay. No payment is taken here and no card is collected. Preferences - a bed type, a floor, a late arrival - ride along on the booking as requests.`
601
621
  : v.demo
602
- ? `Makes a demonstration booking request for the trip's rooms, for a named guest: it returns a confirmation code and the moment the demonstration hold lapses on its own. ${v.brand} does not receive it and no real room is held. No payment is taken and no card is collected. Preferences - a bed type, a floor, a late arrival - ride along on the request.`
622
+ ? `Makes a booking request for the trip's rooms, for a named guest: it returns a confirmation code and the moment the hold lapses on its own. ${v.brand} does not receive it and no real room is held. No payment is taken and no card is collected. Preferences - a bed type, a floor, a late arrival - ride along on the request.`
603
623
  : `Asks ${v.brand} to hold the trip's rooms for a named guest and returns a confirmation code and the moment the hold lapses. No payment is taken and no card is collected; the rooms are held, not paid for. Preferences - a bed type, a floor, a late arrival - ride along on the booking as requests the desk tries to meet.`,
604
624
  annotations: books(v.market ? `Request a booking on ${v.brand}` : `Request a ${v.brand} booking`, open),
605
625
  inputSchema: {
@@ -1709,7 +1729,7 @@ const holderOf = (deps, supplier) => {
1709
1729
  demo: s.mode !== 'live',
1710
1730
  sandbox: s.mode === 'sandbox',
1711
1731
  test: s.mode === 'test',
1712
- notReal: !!deps.vocab.market && s.mode !== 'live',
1732
+ notReal: s.mode !== 'live' && s.mode !== 'test',
1713
1733
  };
1714
1734
  return {
1715
1735
  name: deps.vocab.brand,
@@ -1717,7 +1737,7 @@ const holderOf = (deps, supplier) => {
1717
1737
  demo: deps.vocab.demo,
1718
1738
  sandbox: !!deps.vocab.sandbox,
1719
1739
  test: !!deps.vocab.test,
1720
- notReal: false,
1740
+ notReal: deps.vocab.demo && !deps.vocab.test,
1721
1741
  };
1722
1742
  };
1723
1743
  /**
@@ -1796,17 +1816,14 @@ const paidLine = (deps, b, fee) => {
1796
1816
  const back = formatMoney(p.refundAmount ?? p.amount);
1797
1817
  const whole = !p.refundAmount || p.refundAmount.minor === p.amount.minor;
1798
1818
  const unionpay = p.method === 'unionpay';
1799
- // ⚠️ ONE WORD PER ENVIRONMENT (0.54.0, M9): simulated on the simulated copy, test on a
1800
- // group's test system - and in a market neither, only the fact (`notReal`). A
1801
- // simulation names no "test card" or "UnionPay's test system": that is the payment
1802
- // channel's own environment, not the simulation's word.
1819
+ // ⚠️ THE FACT, NO ENVIRONMENT'S NAME (robin, 2026-11-03): no real money moves, and
1820
+ // the booking was not sent to the group - or, in its own test system, holds no
1821
+ // room for anyone.
1803
1822
  const test = h.notReal
1804
- ? ` No real money moves, and this is not a real booking with ${h.name}.`
1805
- : h.sandbox
1806
- ? ' This is simulated: no real money moves, and the booking is a simulated booking.'
1807
- : h.test
1808
- ? ` This is a test: ${unionpay ? "UnionPay's test system" : 'the card page in test mode'}, no real money moves, and the booking is a test booking in ${h.name}'s test system.`
1809
- : '';
1823
+ ? ` No real money moves, and this booking was not sent to ${h.name}.`
1824
+ : h.test
1825
+ ? ' No real money moves, and this booking holds no room for anyone.'
1826
+ : '';
1810
1827
  const ended = b.status === 'cancelled' || b.status === 'expired' || b.status === 'failed';
1811
1828
  const said = (() => {
1812
1829
  // Its money as it stands once the stay has ended - never "if it does not take it".
@@ -1913,13 +1930,11 @@ const heldLine = (deps, b) => {
1913
1930
  const total = formatMoney(b.quote.total);
1914
1931
  const h = holderOf(deps, b.supplier);
1915
1932
  if (h.caps.booking === 'pay-at-hotel') {
1916
- // ⚠️ A MARKET'S GROUP: the fact, in no environment's word (robin, 2026-11-03).
1933
+ // ⚠️ THE FACT, IN NO ENVIRONMENT'S WORD (robin, 2026-11-03).
1917
1934
  if (h.notReal)
1918
1935
  return `${total} all in. **This booking was not sent to ${h.name}** - no room is held for anyone and nothing is paid, now or at any hotel.`;
1919
- if (h.sandbox)
1920
- return `${total} in the simulated system. **This is a simulated booking** - not a ${h.name} reservation: no room is held and nothing is paid, now or at any hotel.`;
1921
1936
  if (h.test)
1922
- return `${total} in ${h.name}'s test system. **This is a test booking** - it holds no room for anyone, nothing is paid, now or at any hotel, and nobody needs to go there.`;
1937
+ return `${total} all in. **This booking holds no room for anyone** - nothing is paid, now or at any hotel, and nobody needs to go there.`;
1923
1938
  return b.status === 'requested'
1924
1939
  ? `${total} all in, to be paid at the hotel. ${h.name} has not confirmed this booking yet - that takes up to eight minutes, and ${deps.tools.listBookings} shows when it has. Nothing has been charged.`
1925
1940
  : `${total} all in, paid at the hotel. **Nothing has been charged here** - this is ${h.name}'s own reservation, kept until it is cancelled, and the guest pays at check-in.`;
@@ -1936,14 +1951,14 @@ const heldLine = (deps, b) => {
1936
1951
  // nothing for a real stay; said as how long it lasts, and that it is only the
1937
1952
  // demonstration.
1938
1953
  if (h.demo)
1939
- return `${total} all in. **${demoBookingWords(h)}** Nothing has been charged and no card is needed. ${demoHoldWords(b, deps.trips.now(), h)}`;
1954
+ return `${total} all in. **${demoBookingWords(h)}** Nothing has been charged and no card is needed. ${demoHoldWords(b, deps.trips.now())}`;
1940
1955
  return `${total} all in. **Nothing has been charged** - the rooms are held until ${lapses}, and the guest presents a card at check-in.`;
1941
1956
  };
1942
1957
  /**
1943
1958
  * How long a demonstration hold lasts, as "in N minutes" from now - the hold
1944
1959
  * lapses by itself, and says nothing about the stay (T2, `heldLine`).
1945
1960
  */
1946
- const demoHoldWords = (b, now, h) => {
1961
+ const demoHoldWords = (b, now) => {
1947
1962
  const minutes = b.holdUntil ? Math.ceil((Date.parse(b.holdUntil) - now) / 60_000) : Number.NaN;
1948
1963
  if (Number.isNaN(minutes))
1949
1964
  return '';
@@ -1954,15 +1969,11 @@ const demoHoldWords = (b, now, h) => {
1954
1969
  : minutes < 48 * 60
1955
1970
  ? `in about ${Math.round(minutes / 60)} hours`
1956
1971
  : `in about ${Math.round(minutes / (24 * 60))} days`;
1957
- // In a market, no "demonstration" (robin, 2026-11-03): only that it lapses and holds no room.
1958
- if (h.notReal)
1959
- return `It lapses by itself ${lasting} (no real room is held; the stay's own dates are not affected).`;
1960
- return `This is a demonstration: it lapses by itself ${lasting} (demo only - no real room is held; the stay's own dates are not affected).`;
1972
+ // No "demonstration" (robin, 2026-11-03): only that it lapses and holds no room.
1973
+ return `It lapses by itself ${lasting} (no real room is held; the stay's own dates are not affected).`;
1961
1974
  };
1962
- /** What a demonstration booking is, in one sentence - see `demoBookingNote`. */
1963
- const demoBookingWords = (h) => h.notReal
1964
- ? `This booking was not sent to ${h.name}, and ${h.name} is not holding any room.`
1965
- : `This is a demonstration booking: ${h.name} has not received it and is not holding any room.`;
1975
+ /** What a booking that is not sent to the group is, in one sentence - see `demoBookingNote`. */
1976
+ const demoBookingWords = (h) => `This booking was not sent to ${h.name}, and ${h.name} is not holding any room.`;
1966
1977
  /**
1967
1978
  * Said on every answer about a demonstration booking - made, changed or
1968
1979
  * cancelled - and on nothing else: a hold of the demo's that a guest took for
@@ -2011,10 +2022,10 @@ const common = (deps, key) => {
2011
2022
  ? { market: { name: deps.vocab.brand, suppliers: deps.backend.suppliers() } }
2012
2023
  : {}),
2013
2024
  vocab: { noun: deps.vocab.noun, nounPlural: deps.vocab.nounPlural },
2014
- // A market's note is empty (`noteFor`): it labels no environment (robin, 2026-11-03).
2015
- ...(deps.vocab.demo
2016
- ? { demo: true, ...(noteFor(deps.vocab) ? { demoNote: noteFor(deps.vocab) } : {}) }
2017
- : { demo: false }),
2025
+ // ⚠️ NO NOTE ABOUT THE DATA (robin, 2026-11-03: 「不用特意写不是真的」): `demo`
2026
+ // still tells the card a booking here is not a real one, which it says as a
2027
+ // booking's facts; nothing labels the environment.
2028
+ demo: deps.vocab.demo,
2018
2029
  ...(key ? memberBadge(deps, key) : {}),
2019
2030
  ...(langOf(deps, key) ? { lang: langOf(deps, key) } : {}),
2020
2031
  };
@@ -2034,6 +2045,8 @@ const langOf = (deps, _key) => deps.lang;
2034
2045
  * hotel's own clock when the backend knows it, else the instant in UTC - never
2035
2046
  * the date alone (see `atHotelTime`).
2036
2047
  */
2048
+ /** A rate whose own name already says it cannot be refunded - see T10 where a booking is said. */
2049
+ const SAYS_NON_REFUNDABLE = /non-?refundable|不可取消|不可退|不能取消/i;
2037
2050
  const freeUntilText = (r) => r.freeCancellationLocal ??
2038
2051
  `${(r.freeCancellationUntil ?? '').slice(0, 16).replace('T', ' ')} UTC`;
2039
2052
  /** Any Han character: a name already in Chinese needs none beside it. */
@@ -2111,11 +2124,15 @@ const quoteForCard = (quote, groupOf) => ({
2111
2124
  // stepper read 3 and sent 3 ± 1 as the new count (2026-09-28 audit).
2112
2125
  ...(l.ordered !== undefined ? { ordered: l.ordered } : {}),
2113
2126
  unit: formatMoney(l.unit),
2127
+ ...(l.publicUnit ? { publicUnit: formatMoney(l.publicUnit) } : {}),
2114
2128
  total: formatMoney(l.total),
2115
2129
  // The line with its taxes in, where the backend knows them per line: what the
2116
2130
  // review and the trip show, as the hotel's page does (r10 #23).
2117
2131
  ...(l.totalWithTaxes ? { totalWithTaxes: formatMoney(l.totalWithTaxes) } : {}),
2118
2132
  refundable: l.refundable,
2133
+ // The supplier's own sentence about cancelling, where it gives only that
2134
+ // (`QuoteLine.terms`, Otaless): the card says it as it came.
2135
+ ...(l.terms !== undefined ? { terms: l.terms } : {}),
2119
2136
  freeCancellationUntil: l.freeCancellationUntil,
2120
2137
  // The deadline on the hotel's clock, where the backend knows it - the
2121
2138
  // review restates the terms beside the total (round-2 jury).
@@ -2144,7 +2161,20 @@ const quoteForCard = (quote, groupOf) => ({
2144
2161
  // the receipt every guest gets: room, taxes, less the tier, less the
2145
2162
  // coupon, is the total (0.54.0, M1: a member's started from the
2146
2163
  // public rate taxes in, a guest's from the room before them).
2147
- publicSubtotal: formatMoney(money(quote.member.publicTotal.minor - (quote.taxesIncluded ? 0 : quote.taxesAndFees.minor), quote.total.currency)),
2164
+ // ⚠️ THE PUBLIC RATE'S OWN ROOM CHARGE (0.55.0, review r3 N7) where the
2165
+ // backend gives it: the public total less the taxes CHARGED held the public
2166
+ // rate's larger tax as well, and the line's 「公开价每晚 ¥478」 for 2 nights and
2167
+ // 2 rooms (¥1,912) did not meet 「房费(公开价)¥1,922」. The tier's row is then
2168
+ // what it took off the rooms (`roomSaved`), and room, taxes, less the tier,
2169
+ // less the coupon is still the total.
2170
+ publicSubtotal: formatMoney(quote.member.publicSubtotal ??
2171
+ money(quote.member.publicTotal.minor -
2172
+ (quote.taxesIncluded ? 0 : quote.taxesAndFees.minor), quote.total.currency)),
2173
+ ...(quote.member.publicSubtotal
2174
+ ? {
2175
+ roomSaved: formatMoney(money(quote.member.publicSubtotal.minor - quote.subtotal.minor, quote.total.currency)),
2176
+ }
2177
+ : {}),
2148
2178
  memberTotal: formatMoney(money(quote.member.publicTotal.minor - quote.member.saved.minor, quote.total.currency)),
2149
2179
  },
2150
2180
  }
@@ -2275,13 +2305,11 @@ const memberTripLines = (q) => {
2275
2305
  const couponRefusedLine = (q) => q.couponRefused
2276
2306
  ? `The coupon ${q.couponRefused.name ? couponName({ name: q.couponRefused.name, names: q.couponRefused.names }) : q.couponRefused.id} was NOT taken off: ${q.couponRefused.why} The total is without it.`
2277
2307
  : '';
2278
- const tripText = (quote, demo, noCards) => {
2308
+ const tripText = (quote, noCards) => {
2279
2309
  // ⚠️ NOT "EMPTY" WHEN SOMETHING WAS LEFT OUT: a trip whose only group did not
2280
2310
  // answer is not an empty trip (2026-11-03 review, C5).
2281
2311
  if (quote.lines.length === 0 && quote.dropped?.length)
2282
- return [...quote.dropped.map((d) => `Left out: ${d.title} — ${d.why}`), demo ? DEMO_NOTE : '']
2283
- .filter(Boolean)
2284
- .join('\n');
2312
+ return quote.dropped.map((d) => `Left out: ${d.title} — ${d.why}`).join('\n');
2285
2313
  if (quote.lines.length === 0)
2286
2314
  return 'The trip is empty.';
2287
2315
  const lines = quote.lines.map((l) => l.kind === 'room'
@@ -2293,7 +2321,6 @@ const tripText = (quote, demo, noCards) => {
2293
2321
  couponRefusedLine(quote),
2294
2322
  ...memberTripLines(quote),
2295
2323
  ...(quote.dropped ?? []).map((d) => `Left out: ${d.title} — ${d.why}`),
2296
- demo ? DEMO_NOTE : '',
2297
2324
  ]
2298
2325
  .filter(Boolean)
2299
2326
  .join('\n');
@@ -2565,12 +2592,20 @@ export const notSoldHereWords = (group) => `Rates marked paid in advance are lis
2565
2592
  export const notOnSaleWords = (group, why) => `${why.replace(/[.\s]+$/, '')} - ${NOT_SOLD_OUT}. To book it, the guest can use ${group}'s own channels: its app, its website or by phone.`;
2566
2593
  /** The group a hotel is with, by name - the deployment's own brand outside a market. */
2567
2594
  const groupNameOf = (deps, hotelId) => holderOf(deps, deps.backend.supplierOf?.(hotelId)).name;
2595
+ /** A rate's cancellation terms in the supplier's own words (`Room.terms`), quoted - or that none were given. */
2596
+ export const termsWords = (terms) => terms
2597
+ ? `cancellation terms, in the hotel group's own words: "${terms}"`
2598
+ : 'no cancellation terms given';
2568
2599
  /** What a rate says about cancelling, as the text puts it. */
2569
- const cancelWords = (r) => r.freeCancellationUntil
2570
- ? `free to cancel until ${freeUntilText(r)}`
2571
- : r.refundable
2572
- ? 'the free cancellation window has closed - cancelling now has a fee'
2573
- : 'non-refundable';
2600
+ const cancelWords = (r) =>
2601
+ // The supplier's own sentence, as it came - see `Room.terms`.
2602
+ r.terms !== undefined
2603
+ ? termsWords(r.terms)
2604
+ : r.freeCancellationUntil
2605
+ ? `free to cancel until ${freeUntilText(r)}`
2606
+ : r.refundable
2607
+ ? 'the free cancellation window has closed - cancelling now has a fee'
2608
+ : 'non-refundable';
2574
2609
  /**
2575
2610
  * What a room is, in a parenthesis: its beds, how many it sleeps and - for one
2576
2611
  * rate, not a type whose rates differ - breakfast, unless the rate's labels
@@ -2731,7 +2766,11 @@ const heldRoomsWords = (b) => b.quote.lines
2731
2766
  : l.freeCancellationUntil
2732
2767
  ? `, free to cancel until ${freeUntilText(l)}`
2733
2768
  : l.refundable === false
2734
- ? ', non-refundable'
2769
+ ? // ⚠️ NOT TWICE (0.55.0, review r3 T10): 「… · Non-refundable(… · 不可取消),
2770
+ // non-refundable」 - a rate whose name says it is not told it again.
2771
+ SAYS_NON_REFUNDABLE.test(`${l.title} ${Object.values(l.titleNames ?? {}).join(' ')}`)
2772
+ ? ''
2773
+ : ', non-refundable'
2735
2774
  : l.refundable
2736
2775
  ? ', past its free cancellation - cancelling has a fee'
2737
2776
  : ''}`)
@@ -2961,12 +3000,19 @@ const listAnd = (xs) => xs.length > 1 ? `${xs.slice(0, -1).join(', ')} and ${xs.
2961
3000
  */
2962
3001
  const degradedOf = (deps, answer,
2963
3002
  /** What is missing from the list: the hotels of a search, the bookings of "my bookings". */
2964
- noun = deps.vocab.nounPlural) => {
3003
+ noun = deps.vocab.nounPlural,
3004
+ /**
3005
+ * The client draws no card: each group's own Chinese name goes beside its
3006
+ * name, as a hotel's does (`withZh`) - told only "JI Hotel", a model with no
3007
+ * card called it 锦江之星, another group (11-03, text-only eval). A card host
3008
+ * is told the English name alone; the card says the group in its own words.
3009
+ */
3010
+ noCards = false) => {
2965
3011
  const down = answer.degraded ?? [];
2966
3012
  if (down.length === 0)
2967
3013
  return { structured: {}, said: '' };
2968
3014
  const one = down.length === 1;
2969
- const said = `${listAnd(down.map((d) => d.name))} did not answer in time, so none of ${one ? 'its' : 'their'} ${noun} is in this list - this does not mean ${one ? 'it has' : 'they have'} none here; asking again in a moment may bring them.`;
3015
+ const said = `${listAnd(down.map((d) => withZh(d.name, d.names, noCards)))} did not answer in time, so none of ${one ? 'its' : 'their'} ${noun} is in this list - this does not mean ${one ? 'it has' : 'they have'} none here; asking again in a moment may bring them.`;
2970
3016
  return {
2971
3017
  structured: {
2972
3018
  degraded: down.map((d) => ({ supplier: d.supplier, name: d.name })),
@@ -3274,7 +3320,9 @@ const currentTrip = async (deps, key, who, store = key, coupon, ctx) => {
3274
3320
  // came back "needs a phone number". Whose need it is is the trip's groups',
3275
3321
  // as `requestBooking` judges it.
3276
3322
  const nextStep = ctx?.noCards && parts.some((p) => p.lines.some((l) => l.kind === 'room'))
3277
- ? `Nothing in the trip is booked yet. To book it, ${deps.tools.requestBooking} takes the guest's own ${guestDetailsFor(deps, lines.filter((l) => l.kind === 'room'))} - ask for them if the guest has not typed them in this conversation.`
3323
+ ? (deps.backend.capabilities ?? FULL_CAPABILITIES).readOnly
3324
+ ? readOnlyWords(deps.vocab)
3325
+ : `Nothing in the trip is booked yet. To book it, ${deps.tools.requestBooking} takes the guest's own ${guestDetailsFor(deps, lines.filter((l) => l.kind === 'room'))} - ask for them if the guest has not typed them in this conversation.`
3278
3326
  : '';
3279
3327
  if (parts.length === 1 && only) {
3280
3328
  return {
@@ -3288,13 +3336,7 @@ const currentTrip = async (deps, key, who, store = key, coupon, ctx) => {
3288
3336
  count: lines.length,
3289
3337
  ...(nextStep ? { nextStep } : {}),
3290
3338
  },
3291
- text: [
3292
- tripText(only, false, ctx?.noCards),
3293
- ...overlaps.map((o) => o.said),
3294
- orphans.line,
3295
- nextStep,
3296
- deps.vocab.demo && lines.length ? noteFor(deps.vocab) : '',
3297
- ]
3339
+ text: [tripText(only, ctx?.noCards), ...overlaps.map((o) => o.said), orphans.line, nextStep]
3298
3340
  .filter(Boolean)
3299
3341
  .join('\n'),
3300
3342
  };
@@ -3336,11 +3378,10 @@ const currentTrip = async (deps, key, who, store = key, coupon, ctx) => {
3336
3378
  },
3337
3379
  text: [
3338
3380
  `This trip is in ${parts.length} currencies, priced separately and not converted - each hotel is booked and paid in its own.`,
3339
- ...parts.map((q) => tripText(q, false, ctx?.noCards)),
3381
+ ...parts.map((q) => tripText(q, ctx?.noCards)),
3340
3382
  ...overlaps.map((o) => o.said),
3341
3383
  orphans.line,
3342
3384
  nextStep,
3343
- deps.vocab.demo ? noteFor(deps.vocab) : '',
3344
3385
  ]
3345
3386
  .filter(Boolean)
3346
3387
  .join('\n\n'),
@@ -3749,11 +3790,13 @@ const comparedInWords = (c) => {
3749
3790
  const priced = p
3750
3791
  ? [
3751
3792
  `${withZh(p.room, p.roomNames, true)} at ${p.nightly} ${nightWords(true)}, ${p.stayTotal} for the stay incl. taxes and fees`,
3752
- p.freeCancellationUntil
3753
- ? `free to cancel until ${freeUntilText(p)}`
3754
- : p.refundable
3755
- ? 'no free cancellation'
3756
- : 'non-refundable',
3793
+ p.terms !== undefined
3794
+ ? termsWords(p.terms)
3795
+ : p.freeCancellationUntil
3796
+ ? `free to cancel until ${freeUntilText(p)}`
3797
+ : p.refundable
3798
+ ? 'no free cancellation'
3799
+ : 'non-refundable',
3757
3800
  p.payment === 'prepaid'
3758
3801
  ? p.notSoldHere
3759
3802
  ? 'paid in advance - not booked here'
@@ -4063,7 +4106,6 @@ const bookedFromThisForm = async (deps, ctx, key, args) => {
4063
4106
  notUsed?.said ?? '',
4064
4107
  `**${confirming(deps, b) ? 'Being confirmed' : b.confirmationCode}** · ${b.hotelName} · ${stayWords(b.stay, b.hourly)}`,
4065
4108
  bookedLine(deps, b) ?? '',
4066
- deps.vocab.demo ? noteFor(deps.vocab) : '',
4067
4109
  ]
4068
4110
  .filter(Boolean)
4069
4111
  .join('\n'),
@@ -4644,7 +4686,6 @@ const bookTripLines = async (deps, t, ctx, key, store, args, nothingThere) => {
4644
4686
  ...failedText,
4645
4687
  remembered?.line ?? '',
4646
4688
  others ? `The trip's other stays are still in it, not booked:\n${rest?.text ?? ''}` : '',
4647
- deps.vocab.demo ? noteFor(deps.vocab) : '',
4648
4689
  ]
4649
4690
  .filter(Boolean)
4650
4691
  .join('\n'),
@@ -5028,7 +5069,7 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
5028
5069
  : `${c.name} (${c.count})`)
5029
5070
  .join(', ');
5030
5071
  const n = deps.vocab.nounPlural;
5031
- const degraded = degradedOf(deps, answer);
5072
+ const degraded = degradedOf(deps, answer, undefined, ctx?.noCards);
5032
5073
  if (namedCountry) {
5033
5074
  const [only] = countries;
5034
5075
  return {
@@ -5065,13 +5106,19 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
5065
5106
  ask: { ...stayArgs },
5066
5107
  ...(ask.stay ? { stay: ask.stay } : {}),
5067
5108
  ...(today ? { today } : {}),
5109
+ // ⚠️ IN A MARKET, HOW MANY HOTELS EACH GROUP HAS HERE (11-03): the card
5110
+ // says "from N groups" of the groups that have one - not of every group
5111
+ // on the market's list, six of which may have none. Only the counts.
5112
+ ...(deps.backend.suppliers && answer.refine?.suppliers
5113
+ ? { refine: { suppliers: answer.refine.suppliers } }
5114
+ : {}),
5068
5115
  ...degraded.structured,
5069
5116
  },
5070
5117
  text: `${total} ${branded(deps.vocab, n)} in ${facets.cities.length} cities across ${countries.length} ${countries.length === 1 ? 'country' : 'countries'}, to choose from by region, country and city - ${regions.map((r) => `${r.name}: ${ctx.noCards ? everyWithCities(r.countries) : every(r.countries)}`).join('; ')}. A city or a country lists its ${n}. ${degraded.said ? `${degraded.said} ` : ''}${forPlans}`,
5071
5118
  };
5072
5119
  }
5073
5120
  if (hotels.length === 0) {
5074
- const degraded = degradedOf(deps, answer);
5121
+ const degraded = degradedOf(deps, answer, undefined, ctx?.noCards);
5075
5122
  const nearest = (answer.nearest ?? []).map((h) => ({
5076
5123
  ...h,
5077
5124
  summary: hotelText('description', h.name, h.summary, DESCRIPTION_MAX).text,
@@ -5218,7 +5265,7 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
5218
5265
  priceNotes.push(notSold);
5219
5266
  // Every one by name and city, and that there are no others - or, told
5220
5267
  // only "2 hotels", the model asked for the list again to learn which.
5221
- const degraded = degradedOf(deps, answer);
5268
+ const degraded = degradedOf(deps, answer, undefined, ctx?.noCards);
5222
5269
  const inAll = homeList
5223
5270
  ? `There are ${total} ${branded(deps.vocab, deps.vocab.nounPlural)} here in all, and this answer lists every one: ${hotels
5224
5271
  .map((h) => `${hotelName(h.name)}${h.city ? ` in ${h.city}` : ''}`)
@@ -5424,12 +5471,21 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
5424
5471
  const notSold = enough.some((r) => r.notSoldHere)
5425
5472
  ? notSoldHereWords(groupNameOf(deps, h.id))
5426
5473
  : '';
5427
- const rooms = enough.map((r) => ({
5474
+ const rooms = enough.map(({ roomsLeft, refundable, ...r }) => ({
5428
5475
  ...r,
5429
- facets: facetsOf(r),
5476
+ // ⚠️ NO COUNT WHERE THE SUPPLIER GIVES NONE, and no yes / no on
5477
+ // cancelling beside its own sentence (`Room.uncounted`, `Room.terms`).
5478
+ ...(r.uncounted ? {} : { roomsLeft }),
5479
+ ...(r.terms !== undefined ? {} : { refundable }),
5480
+ facets: facetsOf({ ...r, roomsLeft, refundable }),
5430
5481
  nightly: formatMoney(r.nightly),
5431
5482
  stayTotal: formatMoney(r.stayTotal),
5432
- taxesAndFees: formatMoney(r.taxesAndFees),
5483
+ // ⚠️ "INCLUDED", NOT "¥0", where the supplier's price has its taxes in and
5484
+ // gives no split (`Room.terms`, Otaless): told "taxesAndFees ¥0", the
5485
+ // model said "税费 ¥0" - no tax - of a price the group says includes it.
5486
+ taxesAndFees: r.terms !== undefined && r.taxesAndFees.minor === 0
5487
+ ? 'Included'
5488
+ : formatMoney(r.taxesAndFees),
5433
5489
  // ⚠️ THE NUMBER THE GUEST IS LOOKING AT HAS TO BE THE ONE THEY ASKED FOR.
5434
5490
  // With two rooms picked, the card was still showing one room's total and
5435
5491
  // nothing said so - robin changed the count and watched the price not
@@ -5478,7 +5534,6 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
5478
5534
  ? `${flex.text} (That is the cheapest room of any kind, not only one with ${termWords(terms)}.)`
5479
5535
  : flex.text,
5480
5536
  notSold,
5481
- deps.vocab.demo ? noteFor(deps.vocab) : '',
5482
5537
  ]
5483
5538
  .filter(Boolean)
5484
5539
  .join('\n'),
@@ -5521,7 +5576,7 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
5521
5576
  total = found.total;
5522
5577
  degradedFound = found;
5523
5578
  }
5524
- const degraded = degradedOf(deps, degradedFound);
5579
+ const degraded = degradedOf(deps, degradedFound, undefined, ctx?.noCards);
5525
5580
  const unique = [...new Set(ids)];
5526
5581
  // A name that fits more than one is said with the ones it fits; the rest are not found.
5527
5582
  const notFound = dropped.filter((d) => !candidates.some((c) => c.for === d));
@@ -5586,7 +5641,7 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
5586
5641
  // answer says them.
5587
5642
  ...(ctx.noCards
5588
5643
  ? roomTypeLines(rooms, roomsWanted, undefined, true)
5589
- : rooms.map((r) => `- ${r.name} · sleeps ${r.sleeps}${r.breakfast ? ' · breakfast' : ''} · ${formatMoney(r.stayTotal)} for the stay incl. taxes and fees${roomsWanted > 1 ? ` (${formatMoney(multiplyMoney(r.stayTotal, roomsWanted))} for ${roomsWanted} rooms)` : ''}${r.freeCancellationUntil ? `, free to cancel until ${freeUntilText(r)}` : r.refundable ? '' : ', non-refundable'}`)),
5644
+ : rooms.map((r) => `- ${r.name} · sleeps ${r.sleeps}${r.breakfast ? ' · breakfast' : ''} · ${formatMoney(r.stayTotal)} for the stay incl. taxes and fees${roomsWanted > 1 ? ` (${formatMoney(multiplyMoney(r.stayTotal, roomsWanted))} for ${roomsWanted} rooms)` : ''}${r.terms !== undefined ? `, ${termsWords(r.terms)}` : r.freeCancellationUntil ? `, free to cancel until ${freeUntilText(r)}` : r.refundable ? '' : ', non-refundable'}`)),
5590
5645
  ].join('\n')
5591
5646
  : (detail.noRooms ?? `No room type here has ${roomsWanted} left for those nights.`),
5592
5647
  extras.length
@@ -5628,7 +5683,6 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
5628
5683
  ctx.noCards
5629
5684
  ? 'answer with what the guest is told, for a guest who asked to see a list, a hotel or its add-ons.'
5630
5685
  : 'would each draw a card of their own.'}`,
5631
- deps.vocab.demo ? noteFor(deps.vocab) : '',
5632
5686
  ]
5633
5687
  .filter(Boolean)
5634
5688
  .join('\n\n'),
@@ -5712,7 +5766,6 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
5712
5766
  text: extras.length
5713
5767
  ? extras
5714
5768
  .map((e) => `- ${e.name}${ctx.noCards ? ` (\`${e.id}\`)` : ''} — ${formatMoney(e.price)} ${unitWords(e.per)}${held[e.id] ? ` (${booked?.confirmationCode} holds ${held[e.id]})` : ''}`)
5715
- .concat(deps.vocab.demo && noteFor(deps.vocab) ? [noteFor(deps.vocab)] : [])
5716
5769
  .join('\n')
5717
5770
  : `${detail.hotel.name} has no add-ons listed here.`,
5718
5771
  };
@@ -5799,7 +5852,7 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
5799
5852
  const here = await deps.backend.listBookings(who, typeof args.limit === 'number' ? args.limit : undefined);
5800
5853
  // Read here, before a filter or a spread drops it: the groups whose
5801
5854
  // bookings are not in `here` (2026-11-03 review, C5).
5802
- const missing = degradedOf(deps, { degraded: here.degraded }, 'bookings');
5855
+ const missing = degradedOf(deps, { degraded: here.degraded }, 'bookings', ctx?.noCards);
5803
5856
  // Elsewhere, only with the code AND the email - see `listBookings`.
5804
5857
  const code = str(args.booking);
5805
5858
  const { found: there, tooMany } = code && str(args.email)
@@ -6015,7 +6068,6 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
6015
6068
  preview.rule,
6016
6069
  `Say the word and it moves (${t.changeBooking} with \`confirmed\`).`,
6017
6070
  demoBookingNote(deps, preview.supplier),
6018
- deps.vocab.demo ? noteFor(deps.vocab) : '',
6019
6071
  ]
6020
6072
  .filter(Boolean)
6021
6073
  .join(' ')
@@ -6078,7 +6130,6 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
6078
6130
  `${changed.confirmationCode} now holds ${changed.stay.checkIn} to ${changed.stay.checkOut}, ${formatMoney(changed.quote.total)} all in.`,
6079
6131
  'The confirmation code has not changed. **Nothing has been charged.**',
6080
6132
  demoBookingNote(deps, changed.supplier),
6081
- deps.vocab.demo ? noteFor(deps.vocab) : '',
6082
6133
  ]
6083
6134
  .filter(Boolean)
6084
6135
  .join(' '),
@@ -6210,7 +6261,6 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
6210
6261
  ? `Say the word and it is cancelled (${t.cancelBooking} with \`confirmed\`).`
6211
6262
  : '',
6212
6263
  demoBookingNote(deps, preview.supplier),
6213
- deps.vocab.demo ? noteFor(deps.vocab) : '',
6214
6264
  ]
6215
6265
  .filter(Boolean)
6216
6266
  .join(' '),
@@ -6287,20 +6337,14 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
6287
6337
  ? // Paid here in advance: what becomes of the money is the answer.
6288
6338
  `${cancelled.confirmationCode} is ${cancelled.status === 'expired' ? 'called off before it was paid' : 'cancelled'}. ${paidLine(deps, cancelled, charged)}`
6289
6339
  : h.notReal
6290
- ? // A market's group: the fact, in no environment's word (robin, 2026-11-03).
6340
+ ? // The fact, in no environment's word (robin, 2026-11-03); nobody charges
6341
+ // a booking that was never sent anything (2026-10-05 audit, P2).
6291
6342
  `${cancelled.confirmationCode} is cancelled. ${charged.minor === 0 ? 'No fee.' : `A real booking on this rate would be charged ${formatMoney(charged)}; this booking was never sent to ${h.name}, and nothing is charged.`}`
6292
- : h.sandbox
6293
- ? // A simulated booking cancelled in the simulation: no hotel, no charge (2026-10-05 audit, P2).
6294
- `${cancelled.confirmationCode} is cancelled in the simulated system. ${charged.minor === 0 ? 'No fee.' : `A real booking on this rate would be charged ${formatMoney(charged)}; this one is simulated, and nothing is charged.`}`
6295
- : h.test
6296
- ? `${cancelled.confirmationCode} is cancelled in ${h.name}'s test system. ${charged.minor === 0 ? 'No fee.' : `A live booking on this rate would be charged ${formatMoney(charged)}; this one is a test, and nothing is charged.`}`
6297
- : h.demo
6298
- ? // Nobody charges a demonstration anything (2026-10-05 audit, P2).
6299
- `${cancelled.confirmationCode} is cancelled. ${charged.minor === 0 ? 'No fee.' : `A real booking on this rate would be charged ${formatMoney(charged)}; this is a demonstration, and nothing is charged.`}`
6300
- : `${cancelled.confirmationCode} is cancelled. ${charged.minor === 0 ? 'No fee.' : `The hotel charges ${formatMoney(charged)}.`}`,
6343
+ : h.test
6344
+ ? `${cancelled.confirmationCode} is cancelled. ${charged.minor === 0 ? 'No fee.' : `A real booking on this rate would be charged ${formatMoney(charged)}; this booking held no room for anyone, and nothing is charged.`}`
6345
+ : `${cancelled.confirmationCode} is cancelled. ${charged.minor === 0 ? 'No fee.' : `The hotel charges ${formatMoney(charged)}.`}`,
6301
6346
  couponNow?.said ?? '',
6302
6347
  demoBookingNote(deps, cancelled.supplier),
6303
- deps.vocab.demo ? noteFor(deps.vocab) : '',
6304
6348
  ]
6305
6349
  .filter(Boolean)
6306
6350
  .join(' '),
@@ -6384,7 +6428,6 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
6384
6428
  : '',
6385
6429
  ...comparison.dropped.map((d) => `Left out: ${d.name} — ${d.why}`),
6386
6430
  ...fitsManyOf(deps, comparison.dropped),
6387
- deps.vocab.demo ? noteFor(deps.vocab) : '',
6388
6431
  ]
6389
6432
  .filter(Boolean)
6390
6433
  .join('\n'),
@@ -6450,11 +6493,13 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
6450
6493
  // With no card, until when it is free to cancel too: the reply is told to
6451
6494
  // give each stay's terms (2026-11-02 audit, P2-3).
6452
6495
  const termsOf = (x) => [
6453
- x.refundable === false
6454
- ? 'non-refundable'
6455
- : ctx.noCards && x.freeCancellationUntil
6456
- ? `free to cancel until ${freeUntilText(x)}`
6457
- : '',
6496
+ x.terms
6497
+ ? `cancellation: "${x.terms}"`
6498
+ : x.refundable === false
6499
+ ? 'non-refundable'
6500
+ : ctx.noCards && x.freeCancellationUntil
6501
+ ? `free to cancel until ${freeUntilText(x)}`
6502
+ : '',
6458
6503
  x.payment === 'prepaid'
6459
6504
  ? x.notSoldHere
6460
6505
  ? 'paid in advance - not booked here'
@@ -6510,7 +6555,6 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
6510
6555
  ...fitsManyOf(deps, plan.dropped),
6511
6556
  uncheckedSaid,
6512
6557
  ctx.noCards ? PLAN_NOT_DRAWN : PLAN_DRAWN_ONCE,
6513
- deps.vocab.demo ? noteFor(deps.vocab) : '',
6514
6558
  ]
6515
6559
  .filter(Boolean)
6516
6560
  .join('\n'),
@@ -6566,7 +6610,6 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
6566
6610
  member.preferences?.length
6567
6611
  ? `Saved preferences on this membership: ${member.preferences.map((k) => REQUEST_WORDS[k]).join(', ')}. They are ticked on the booking form; mention them, and ask before booking with them.`
6568
6612
  : '',
6569
- deps.vocab.demo ? noteFor(deps.vocab) : '',
6570
6613
  ]
6571
6614
  .filter(Boolean)
6572
6615
  .join('\n'),