@danceiny/gotry 0.0.1-rc.15 → 0.0.1-rc.17

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 (238) hide show
  1. package/README.md +51 -13
  2. package/README.zh-CN.md +26 -12
  3. package/bin/gotry-booking-copilot.js +53 -0
  4. package/bin/gotry-bootstrap.js +357 -8
  5. package/bin/gotry-inner.js +442 -60
  6. package/bin/gotry-runtime-resolution.d.ts +27 -0
  7. package/bin/gotry-runtime-resolution.js +50 -0
  8. package/bin/gotry.js +1 -1
  9. package/cordis.gotry-patch.yml +15 -1
  10. package/data/airline-airports.json +39 -0
  11. package/dist/capabilities/agent-reach-deep.js +1 -1
  12. package/dist/capabilities/agent-reach.js +1 -1
  13. package/dist/capabilities/anything.js +1 -1
  14. package/dist/capabilities/artifacts.js +1 -1
  15. package/dist/capabilities/effect.js +293 -0
  16. package/dist/capabilities/fact-log.js +41 -0
  17. package/dist/capabilities/flyai.js +20 -6
  18. package/dist/capabilities/hbcli.js +43 -1
  19. package/dist/capabilities/incident-log.js +1 -1
  20. package/dist/capabilities/model-override.js +18 -0
  21. package/dist/capabilities/opensky.js +1 -1
  22. package/dist/capabilities/resilience.js +90 -0
  23. package/dist/capabilities/session/action-cache.js +1 -1
  24. package/dist/capabilities/session/adapters/ctrip-flight.js +1 -1
  25. package/dist/capabilities/session/adapters/meituan-local.js +1 -1
  26. package/dist/capabilities/session/benchmark.js +2 -1
  27. package/dist/capabilities/session/extension-bridge.js +358 -0
  28. package/dist/capabilities/session/extension-channel.js +93 -0
  29. package/dist/capabilities/session/extension-distribution.js +234 -0
  30. package/dist/capabilities/session/extract.js +1 -1
  31. package/dist/capabilities/session/golden-score.js +92 -0
  32. package/dist/capabilities/session/health-watch.js +216 -0
  33. package/dist/capabilities/session/read-guard.js +1 -1
  34. package/dist/capabilities/session/static-flight-golden.js +137 -0
  35. package/dist/capabilities/session/transport.js +1 -1
  36. package/dist/capabilities/session/wizard.js +147 -0
  37. package/dist/capabilities/session-consent.js +1 -1
  38. package/dist/capabilities/session-login.js +83 -1
  39. package/dist/capabilities/session-search.js +111 -2
  40. package/dist/capabilities/weather.js +168 -46
  41. package/dist/data/session-golden-20.json +25 -0
  42. package/dist/data/sf-golden-manifest.json +102 -0
  43. package/dist/data/sf-static-routes.json +91 -0
  44. package/dist/scripts/action-cache-tests.js +1 -1
  45. package/dist/scripts/agent-planning-budget-e2e.js +227 -0
  46. package/dist/scripts/agent-planning-budget-tests.js +173 -0
  47. package/dist/scripts/agent-reach-deep-tests.js +1 -1
  48. package/dist/scripts/agent-reach-tests.js +1 -1
  49. package/dist/scripts/agent-reach-wrapper-tests.js +1 -1
  50. package/dist/scripts/anything-tests.js +1 -1
  51. package/dist/scripts/async-collect.js +1 -1
  52. package/dist/scripts/benchmark-environment-bridge-e2e.js +981 -0
  53. package/dist/scripts/benchmark-environment-bridge-tests.js +2544 -0
  54. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +335 -0
  55. package/dist/scripts/booking-copilot-availability-policy-v2-tests.js +1355 -0
  56. package/dist/scripts/booking-copilot-bin-proof-tests.js +89 -0
  57. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +113 -0
  58. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +356 -0
  59. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +557 -0
  60. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +140 -0
  61. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +202 -0
  62. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +102 -0
  63. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +374 -0
  64. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +447 -0
  65. package/dist/scripts/booking-copilot-runtime-proof-tests.js +205 -0
  66. package/dist/scripts/booking-copilot-server-proof-tests.js +317 -0
  67. package/dist/scripts/booking-copilot-startup-proof-tests.js +283 -0
  68. package/dist/scripts/booking-copilot-v2-runtime-proof-tests.js +3935 -0
  69. package/dist/scripts/booking-saga-tests.js +1 -1
  70. package/dist/scripts/booking-surface-contract-proof-tests.js +393 -0
  71. package/dist/scripts/booking-surface-v2-contract-proof-tests.js +1174 -0
  72. package/dist/scripts/bootstrap-tests.js +59 -3
  73. package/dist/scripts/build-changelog.js +279 -0
  74. package/dist/scripts/changelog-tests.js +165 -0
  75. package/dist/scripts/companion-tests.js +1 -1
  76. package/dist/scripts/diff-test.js +1 -1
  77. package/dist/scripts/dsh-runtime-closure-tests.js +225 -0
  78. package/dist/scripts/dsh-runtime-closure.js +150 -0
  79. package/dist/scripts/effect-tests.js +474 -0
  80. package/dist/scripts/engine-run.js +1 -1
  81. package/dist/scripts/engine-tests.js +1 -1
  82. package/dist/scripts/evaluation-cadence-tests.js +347 -0
  83. package/dist/scripts/evaluation-contract-tests.js +574 -0
  84. package/dist/scripts/extension-distribution-cli.js +35 -0
  85. package/dist/scripts/extension-distribution-tests.js +341 -0
  86. package/dist/scripts/extension-tests.js +573 -0
  87. package/dist/scripts/fact-gate-tests.js +318 -0
  88. package/dist/scripts/flyai-tests.js +1 -1
  89. package/dist/scripts/hbcli-e2e-tests.js +180 -0
  90. package/dist/scripts/hbcli-tests.js +1 -1
  91. package/dist/scripts/health-watch-cli.js +51 -0
  92. package/dist/scripts/i18n-tests.js +1 -1
  93. package/dist/scripts/incident-tests.js +1 -1
  94. package/dist/scripts/journey-tests.js +1 -1
  95. package/dist/scripts/ledger-tests.js +1 -1
  96. package/dist/scripts/ledger-workflow-crash.js +1 -1
  97. package/dist/scripts/memory-capture-tests.js +1 -1
  98. package/dist/scripts/memory-decay-tests.js +1 -1
  99. package/dist/scripts/memory-metrics.js +1 -1
  100. package/dist/scripts/memory-value-report.js +1 -1
  101. package/dist/scripts/model-override-e2e.js +176 -0
  102. package/dist/scripts/nightly-evidence-tests.js +67 -4
  103. package/dist/scripts/nightly-evidence.js +59 -3
  104. package/dist/scripts/nudge-digest.js +1 -1
  105. package/dist/scripts/onboarding-tests.js +186 -0
  106. package/dist/scripts/opensky-check.js +1 -1
  107. package/dist/scripts/opensky-tests.js +1 -1
  108. package/dist/scripts/pnpm-dsh-closure-proof.js +20 -0
  109. package/dist/scripts/price-drift-tests.js +441 -0
  110. package/dist/scripts/price-drift-watch.js +491 -0
  111. package/dist/scripts/probe-poi-tests.js +1 -1
  112. package/dist/scripts/product-metrics.js +1 -1
  113. package/dist/scripts/publish-preverify.js +40 -4
  114. package/dist/scripts/realtime-pricing-tests.js +1 -1
  115. package/dist/scripts/replay-async.js +1 -1
  116. package/dist/scripts/replay-real.js +1 -1
  117. package/dist/scripts/replay.js +1 -1
  118. package/dist/scripts/session-attach-diagnose.js +1 -1
  119. package/dist/scripts/session-attach-poc.js +1 -1
  120. package/dist/scripts/session-benchmark.js +1 -1
  121. package/dist/scripts/session-extract-tests.js +1 -1
  122. package/dist/scripts/session-login.js +1 -1
  123. package/dist/scripts/session-tests.js +70 -20
  124. package/dist/scripts/sf-live-benchmark.js +338 -0
  125. package/dist/scripts/sf-live-cli-tests.js +21 -0
  126. package/dist/scripts/sf-soft-score-tests.js +108 -0
  127. package/dist/scripts/sf-summary.js +93 -0
  128. package/dist/scripts/skeleton-check.js +1 -1
  129. package/dist/scripts/skeleton-integration-test.js +1 -1
  130. package/dist/scripts/skills-contract-tests.js +1 -1
  131. package/dist/scripts/smoke-session-gate-tests.js +29 -0
  132. package/dist/scripts/smoke.js +154 -33
  133. package/dist/scripts/state-cli-tests.js +1 -1
  134. package/dist/scripts/state-cli.js +1 -1
  135. package/dist/scripts/static-golden-tests.js +299 -0
  136. package/dist/scripts/time-eval-tests.js +1 -1
  137. package/dist/scripts/travel-timeline-tests.js +1 -1
  138. package/dist/scripts/unified-tests.js +1 -1
  139. package/dist/scripts/weather-tests.js +694 -44
  140. package/dist/scripts/z3-race-tests.js +1 -1
  141. package/dist/src/artifact-gate.js +310 -0
  142. package/dist/src/benchmark-agent-conformance.js +370 -0
  143. package/dist/src/benchmark-environment-bridge.js +384 -0
  144. package/dist/src/benchmark-headless-child-diagnostics.js +173 -0
  145. package/dist/src/benchmark-tool-isolation.js +124 -0
  146. package/dist/src/bookable-facts.js +349 -0
  147. package/dist/src/booking-saga.js +1 -1
  148. package/dist/src/booking-surface/availability-policy-v2.js +830 -0
  149. package/dist/src/booking-surface/canonical-schema.js +113 -0
  150. package/dist/src/booking-surface/contracts-v2.js +89 -0
  151. package/dist/src/booking-surface/contracts.js +46 -0
  152. package/dist/src/booking-surface/dsh-planner.js +453 -0
  153. package/dist/src/booking-surface/dsh-plugin.js +93 -0
  154. package/dist/src/booking-surface/error-codes.js +94 -0
  155. package/dist/src/booking-surface/index.js +15 -0
  156. package/dist/src/booking-surface/profile.js +68 -0
  157. package/dist/src/booking-surface/runtime-v2.js +1771 -0
  158. package/dist/src/booking-surface/runtime.js +351 -0
  159. package/dist/src/booking-surface/server-v2.js +334 -0
  160. package/dist/src/booking-surface/server.js +302 -0
  161. package/dist/src/booking-surface/startup.js +159 -0
  162. package/dist/src/booking-surface/validation-v2.js +319 -0
  163. package/dist/src/booking-surface/validation.js +809 -0
  164. package/dist/src/bridge.js +1 -1
  165. package/dist/src/companions.js +1 -1
  166. package/dist/src/contracts.js +1 -1
  167. package/dist/src/dsh-llm.js +1 -1
  168. package/dist/src/engine.js +1 -1
  169. package/dist/src/evaluation-cadence.js +234 -0
  170. package/dist/src/evaluation-contracts.js +906 -0
  171. package/dist/src/i18n.js +1 -1
  172. package/dist/src/index.js +234 -60
  173. package/dist/src/journey.js +1 -1
  174. package/dist/src/loop.js +1 -1
  175. package/dist/src/memory-capture.js +1 -1
  176. package/dist/src/memory-decay.js +1 -1
  177. package/dist/src/memory-utility.js +1 -1
  178. package/dist/src/mock-llm.js +1 -1
  179. package/dist/src/model.js +1 -1
  180. package/dist/src/realtime-pricing.js +14 -7
  181. package/dist/src/slot-spec.js +1 -1
  182. package/dist/src/state-ledger.js +2 -1
  183. package/dist/src/time-anchor.js +1 -1
  184. package/dist/src/tool-budget.js +136 -0
  185. package/dist/src/tool-packet.js +1 -1
  186. package/dist/src/travel-slots.js +1 -1
  187. package/dist/src/travel-timeline.js +1 -1
  188. package/dist/src/unified.js +1 -1
  189. package/dist/src/wish-pool.js +1 -1
  190. package/dist/src/z3-shared.js +1 -1
  191. package/extension/README.md +50 -0
  192. package/extension/background.js +160 -0
  193. package/extension/content-bridge.js +41 -0
  194. package/extension/content-main.js +62 -0
  195. package/extension/manifest.json +32 -0
  196. package/package.json +291 -12
  197. package/schemas/booking.surface.v1.schema.json +927 -0
  198. package/schemas/booking.surface.v2.schema.json +61 -0
  199. package/ts/capabilities/fact-log.ts +54 -0
  200. package/ts/capabilities/flyai.ts +16 -3
  201. package/ts/capabilities/hbcli.ts +46 -0
  202. package/ts/capabilities/session/benchmark.ts +4 -1
  203. package/ts/capabilities/session/extension-bridge.ts +377 -0
  204. package/ts/capabilities/session/extension-channel.ts +95 -0
  205. package/ts/capabilities/session/extension-distribution.ts +264 -0
  206. package/ts/capabilities/session/golden-score.ts +139 -0
  207. package/ts/capabilities/session/health-watch.ts +257 -0
  208. package/ts/capabilities/session/static-flight-golden.ts +209 -0
  209. package/ts/capabilities/session/wizard.ts +140 -0
  210. package/ts/capabilities/session-login.ts +63 -2
  211. package/ts/capabilities/session-search.ts +105 -3
  212. package/ts/capabilities/weather.ts +141 -52
  213. package/ts/package.json +3 -3
  214. package/ts/src/artifact-gate.ts +365 -0
  215. package/ts/src/benchmark-agent-conformance.ts +448 -0
  216. package/ts/src/benchmark-environment-bridge.ts +348 -0
  217. package/ts/src/benchmark-headless-child-diagnostics.ts +184 -0
  218. package/ts/src/benchmark-tool-isolation.ts +166 -0
  219. package/ts/src/bookable-facts.ts +557 -0
  220. package/ts/src/booking-surface/availability-policy-v2.ts +523 -0
  221. package/ts/src/booking-surface/canonical-schema.js +113 -0
  222. package/ts/src/booking-surface/contracts-v2.ts +118 -0
  223. package/ts/src/booking-surface/contracts.ts +380 -0
  224. package/ts/src/booking-surface/dsh-planner.ts +452 -0
  225. package/ts/src/booking-surface/dsh-plugin.js +93 -0
  226. package/ts/src/booking-surface/error-codes.ts +101 -0
  227. package/ts/src/booking-surface/index.ts +12 -0
  228. package/ts/src/booking-surface/profile.ts +42 -0
  229. package/ts/src/booking-surface/runtime-v2.ts +1466 -0
  230. package/ts/src/booking-surface/runtime.ts +483 -0
  231. package/ts/src/booking-surface/server-v2.ts +247 -0
  232. package/ts/src/booking-surface/server.ts +324 -0
  233. package/ts/src/booking-surface/startup.ts +196 -0
  234. package/ts/src/booking-surface/validation-v2.ts +205 -0
  235. package/ts/src/booking-surface/validation.ts +453 -0
  236. package/ts/src/index.ts +161 -14
  237. package/ts/src/state-ledger.ts +1 -0
  238. package/ts/src/tool-budget.ts +165 -0
@@ -0,0 +1,61 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://gotry.dev/schemas/booking.surface.v2.schema.json",
4
+ "oneOf": [
5
+ {"$ref":"#/$defs/Workspace"},{"$ref":"#/$defs/Action"},{"$ref":"#/$defs/Receipt"},
6
+ {"$ref":"#/$defs/Ingress"},{"$ref":"#/$defs/UserTurn"},{"$ref":"#/$defs/Continuation"},{"$ref":"#/$defs/Event"}
7
+ ],
8
+ "$defs": {
9
+ "Ref":{"$ref":"https://gotry.dev/schemas/booking.surface.v1.schema.json#/$defs/OpaqueRef"},
10
+ "Hex64":{"type":"string","pattern":"^[0-9a-f]{64}$"},
11
+ "Surface":{"enum":["tenant","customer_portal","storefront","payment_link"]},
12
+ "Kind":{"enum":["search.patch","search.run","results.view.patch","hotel.focus","hotel.select","offers.query","offers.view.patch","offers.compare","offer.select","offer.check","checkout.prepare","order.observe"]},
13
+ "Codes":{"type":"array","minItems":0,"maxItems":28,"uniqueItems":true,"items":{"enum":["byos_mapped_risk","check_avail_failed","check_avail_unverified","component_executor_unavailable","hotel_not_visible","hotel_rates_failed","offer_facts_changed","offer_not_loaded","offer_unavailable","order_not_found","order_outcome_not_observed","order_state_unknown","order_status_unavailable","requested_offers_not_loaded","search_failed","search_form_invalid","search_session_expired","search_terminal_timeout","stale_revision","surface_adapter_failed","undo_token_not_found","unhandled","unsupported","verified_offer_required","workspace_changed_during_action","criterion_must_not_met","no_hotels_matched","offer_target_not_reached"]}},
14
+ "LoadedOffer":{"type":"object","additionalProperties":false,"required":["offerRef","offerVersionRef","hotelRef","evidenceLevel","factRefs"],"properties":{"offerRef":{"$ref":"#/$defs/Ref"},"offerVersionRef":{"$ref":"#/$defs/Ref"},"hotelRef":{"$ref":"#/$defs/Ref"},"evidenceLevel":{"enum":["listed","rate_loaded","checked"]},"factRefs":{"type":"array","maxItems":64,"uniqueItems":true,"items":{"$ref":"#/$defs/Ref"}}}},
15
+ "VerifiedOffer":{"type":"object","additionalProperties":false,"required":["offerRef","offerVersionRef","verifiedOfferRef","expiresAt"],"properties":{"offerRef":{"$ref":"#/$defs/Ref"},"offerVersionRef":{"$ref":"#/$defs/Ref"},"verifiedOfferRef":{"$ref":"#/$defs/Ref"},"expiresAt":{"type":"string","pattern":"^\\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\\d|3[01])T(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d{1,9})?(?:Z|[+-](?:[01]\\d|2[0-3]):[0-5]\\d)$"}}},
16
+ "OfferVersionInput":{"type":"object","additionalProperties":false,"required":["offerRef","offerVersionRef"],"properties":{"offerRef":{"$ref":"#/$defs/Ref"},"offerVersionRef":{"$ref":"#/$defs/Ref"}}},
17
+ "CheckoutPrepareVersionInput":{"type":"object","additionalProperties":false,"required":["offerRef","offerVersionRef","verifiedOfferRef"],"properties":{"offerRef":{"$ref":"#/$defs/Ref"},"offerVersionRef":{"$ref":"#/$defs/Ref"},"verifiedOfferRef":{"$ref":"#/$defs/Ref"}}},
18
+ "Workspace":{"type":"object","additionalProperties":false,"required":["schemaVersion","contextRef","surface","revision","locale","currency","searchDraft","results","visibleHotels","loadedOffers","shortlistedOfferRefs","capabilities"],"properties":{"schemaVersion":{"const":"booking.surface.v2"},"contextRef":{"$ref":"#/$defs/Ref"},"surface":{"$ref":"#/$defs/Surface"},"revision":{"$ref":"https://gotry.dev/schemas/booking.surface.v1.schema.json#/$defs/Revision"},"locale":{"$ref":"https://gotry.dev/schemas/booking.surface.v1.schema.json#/$defs/NonEmptyString"},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"searchDraft":{"$ref":"https://gotry.dev/schemas/booking.surface.v1.schema.json#/$defs/SearchDraftSnapshotV1"},"results":{"$ref":"https://gotry.dev/schemas/booking.surface.v1.schema.json#/$defs/ResultViewSnapshotV1"},"visibleHotels":{"type":"array","maxItems":100,"items":{"$ref":"https://gotry.dev/schemas/booking.surface.v1.schema.json#/$defs/VisibleHotelFactV1"}},"loadedOffers":{"type":"array","maxItems":200,"items":{"$ref":"#/$defs/LoadedOffer"}},"focusedHotelRef":{"$ref":"#/$defs/Ref"},"shortlistedOfferRefs":{"type":"array","maxItems":100,"uniqueItems":true,"items":{"$ref":"#/$defs/Ref"}},"selectedOfferRef":{"$ref":"#/$defs/Ref"},"verifiedOffer":{"$ref":"#/$defs/VerifiedOffer"},"capabilities":{"type":"object","additionalProperties":false,"required":["surface","allowedActions"],"properties":{"surface":{"$ref":"#/$defs/Surface"},"allowedActions":{"type":"array","minItems":1,"maxItems":12,"uniqueItems":true,"items":{"$ref":"#/$defs/Kind"}}}}}},
19
+ "IngressWorkspace":{"type":"object","additionalProperties":false,"required":["schemaVersion","revision","locale","currency","searchDraft","results","visibleHotels","loadedOffers","shortlistedOfferRefs"],"properties":{"schemaVersion":{"const":"booking.surface.v2"},"revision":{"type":"integer","minimum":0},"locale":{"type":"string","minLength":1,"maxLength":64},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"searchDraft":{"$ref":"https://gotry.dev/schemas/booking.surface.v1.schema.json#/$defs/SearchDraftSnapshotV1"},"results":{"$ref":"https://gotry.dev/schemas/booking.surface.v1.schema.json#/$defs/ResultViewSnapshotV1"},"visibleHotels":{"type":"array","maxItems":100,"items":{"$ref":"https://gotry.dev/schemas/booking.surface.v1.schema.json#/$defs/VisibleHotelFactV1"}},"loadedOffers":{"type":"array","maxItems":200,"items":{"$ref":"#/$defs/LoadedOffer"}},"focusedHotelRef":{"$ref":"#/$defs/Ref"},"shortlistedOfferRefs":{"type":"array","maxItems":100,"uniqueItems":true,"items":{"$ref":"#/$defs/Ref"}},"selectedOfferRef":{"$ref":"#/$defs/Ref"}}},
20
+ "PresentationKey":{"type":"string","minLength":1,"maxLength":512},
21
+ "RequestKey":{"type":"string","minLength":8,"maxLength":128,"pattern":"^[A-Za-z0-9][A-Za-z0-9:._-]{7,127}$"},
22
+ "ApprovalRef":{"type":"object","additionalProperties":false,"required":["approvalId","blockerId","contextRef","sourceTurnId","presentationRequestKey","sourceActionId","targetActionId","sourceRevision","targetActionKind","to","expiresAt","nonce","sourceReceiptDigest","scope","code","criterionPath","valueDigest"],"properties":{"approvalId":{"$ref":"#/$defs/Ref"},"blockerId":{"$ref":"#/$defs/Ref"},"contextRef":{"$ref":"#/$defs/Ref"},"sourceTurnId":{"$ref":"#/$defs/Ref"},"presentationRequestKey":{"$ref":"#/$defs/PresentationKey"},"sourceActionId":{"$ref":"#/$defs/Ref"},"targetActionId":{"$ref":"#/$defs/Ref"},"sourceRevision":{"type":"integer","minimum":0},"targetActionKind":{"$ref":"#/$defs/Kind"},"to":{"enum":["prefer","drop"]},"expiresAt":{"type":"string","minLength":1},"nonce":{"$ref":"#/$defs/Ref"},"sourceReceiptDigest":{"$ref":"#/$defs/Hex64"},"scope":{"enum":["search","offer","availability","checkout"]},"code":{"enum":["no_hotels_matched","hotel_not_visible","hotel_rates_failed","criterion_must_not_met","offer_target_not_reached","offer_unavailable"]},"criterionPath":{"type":"string","pattern":"^(searchDraft|results|offers|checkout)(\\.[A-Za-z][A-Za-z0-9_]*){0,3}$","maxLength":160},"valueDigest":{"$ref":"#/$defs/Hex64"}}},
23
+ "ActionBase":{"type":"object","additionalProperties":false,"required":["schemaVersion","kind","actionId","contextRef","expectedRevision","reason","factRefs","input"],"properties":{"schemaVersion":{"const":"booking.surface.v2"},"kind":{"$ref":"#/$defs/Kind"},"actionId":{"$ref":"#/$defs/Ref"},"contextRef":{"$ref":"#/$defs/Ref"},"expectedRevision":{"type":"integer","minimum":0},"reason":{"type":"string","minLength":1,"maxLength":1000},"factRefs":{"type":"array","maxItems":64,"uniqueItems":true,"items":{"$ref":"#/$defs/Ref"}},"input":{"type":"object"},"relaxationApprovalRef":{"$ref":"#/$defs/ApprovalRef"}}},
24
+ "Action":{"oneOf":[
25
+ {"allOf":[{"$ref":"#/$defs/ActionBase"},{"type":"object","properties":{"kind":{"const":"search.patch"},"input":{"$ref":"https://gotry.dev/schemas/booking.surface.v1.schema.json#/$defs/SearchPatchInputV1"}}}]},
26
+ {"allOf":[{"$ref":"#/$defs/ActionBase"},{"type":"object","properties":{"kind":{"const":"search.run"},"input":{"$ref":"https://gotry.dev/schemas/booking.surface.v1.schema.json#/$defs/SearchRunInputV1"}}}]},
27
+ {"allOf":[{"$ref":"#/$defs/ActionBase"},{"type":"object","properties":{"kind":{"const":"results.view.patch"},"input":{"$ref":"https://gotry.dev/schemas/booking.surface.v1.schema.json#/$defs/ResultsViewPatchInputV1"}}}]},
28
+ {"allOf":[{"$ref":"#/$defs/ActionBase"},{"type":"object","properties":{"kind":{"const":"hotel.focus"},"input":{"$ref":"https://gotry.dev/schemas/booking.surface.v1.schema.json#/$defs/HotelFocusInputV1"}}}]},
29
+ {"allOf":[{"$ref":"#/$defs/ActionBase"},{"type":"object","properties":{"kind":{"const":"hotel.select"},"input":{"$ref":"https://gotry.dev/schemas/booking.surface.v1.schema.json#/$defs/HotelSelectInputV1"}}}]},
30
+ {"allOf":[{"$ref":"#/$defs/ActionBase"},{"type":"object","properties":{"kind":{"const":"offers.query"},"input":{"$ref":"https://gotry.dev/schemas/booking.surface.v1.schema.json#/$defs/OffersQueryInputV1"}}}]},
31
+ {"allOf":[{"$ref":"#/$defs/ActionBase"},{"type":"object","properties":{"kind":{"const":"offers.view.patch"},"input":{"$ref":"https://gotry.dev/schemas/booking.surface.v1.schema.json#/$defs/OffersViewPatchInputV1"}}}]},
32
+ {"allOf":[{"$ref":"#/$defs/ActionBase"},{"type":"object","properties":{"kind":{"const":"offers.compare"},"input":{"$ref":"https://gotry.dev/schemas/booking.surface.v1.schema.json#/$defs/OffersCompareInputV1"}}}]},
33
+ {"allOf":[{"$ref":"#/$defs/ActionBase"},{"type":"object","properties":{"kind":{"const":"offer.select"},"input":{"$ref":"#/$defs/OfferVersionInput"}}}]},
34
+ {"allOf":[{"$ref":"#/$defs/ActionBase"},{"type":"object","properties":{"kind":{"const":"offer.check"},"input":{"$ref":"#/$defs/OfferVersionInput"}}}]},
35
+ {"allOf":[{"$ref":"#/$defs/ActionBase"},{"type":"object","properties":{"kind":{"const":"checkout.prepare"},"input":{"$ref":"#/$defs/CheckoutPrepareVersionInput"}}}]},
36
+ {"allOf":[{"$ref":"#/$defs/ActionBase"},{"type":"object","properties":{"kind":{"const":"order.observe"},"input":{"$ref":"https://gotry.dev/schemas/booking.surface.v1.schema.json#/$defs/OrderObserveInputV1"}}}]}
37
+ ]},
38
+ "Approval":{"type":"object","additionalProperties":false,"required":["taskId","contextRef","sourceTurnId","presentationRequestKey","optionDigest","approvalId","deliveryNonce","blockerId","sourceActionId","sourceReceiptDigest","scope","code","criterionPath","valueDigest","from","to","approved"],"properties":{"taskId":{"$ref":"#/$defs/Ref"},"contextRef":{"$ref":"#/$defs/Ref"},"sourceTurnId":{"$ref":"#/$defs/Ref"},"presentationRequestKey":{"$ref":"#/$defs/PresentationKey"},"optionDigest":{"$ref":"#/$defs/Hex64"},"approvalId":{"$ref":"#/$defs/Ref"},"deliveryNonce":{"$ref":"#/$defs/Ref"},"blockerId":{"$ref":"#/$defs/Ref"},"sourceActionId":{"$ref":"#/$defs/Ref"},"sourceReceiptDigest":{"$ref":"#/$defs/Hex64"},"scope":{"enum":["search","offer","availability","checkout"]},"code":{"enum":["no_hotels_matched","hotel_not_visible","hotel_rates_failed","criterion_must_not_met","offer_target_not_reached","offer_unavailable"]},"criterionPath":{"type":"string","pattern":"^(searchDraft|results|offers|checkout)(\\.[A-Za-z][A-Za-z0-9_]*){0,3}$","maxLength":160},"valueDigest":{"$ref":"#/$defs/Hex64"},"from":{"const":"must"},"to":{"enum":["prefer","drop"]},"approved":{"const":true}}},
39
+ "Blocker":{"type":"object","additionalProperties":false,"required":["blockerId","sourceActionId","sourceReceiptDigest","scope","code","criterionPath","strength","valueDigest","evidence"],"properties":{"blockerId":{"$ref":"#/$defs/Ref"},"sourceActionId":{"$ref":"#/$defs/Ref"},"sourceReceiptDigest":{"$ref":"#/$defs/Hex64"},"scope":{"enum":["search","offer","availability","checkout"]},"code":{"enum":["no_hotels_matched","hotel_not_visible","hotel_rates_failed","criterion_must_not_met","offer_target_not_reached","offer_unavailable"]},"criterionPath":{"type":"string","pattern":"^(searchDraft|results|offers|checkout)(\\.[A-Za-z][A-Za-z0-9_]*){0,3}$","maxLength":160},"strength":{"const":"must"},"valueDigest":{"$ref":"#/$defs/Hex64"},"valueLabel":{"type":"string","minLength":1,"maxLength":120},"evidence":{"type":"object","additionalProperties":false,"required":["factRefs","gapCodes"],"properties":{"factRefs":{"type":"array","minItems":1,"maxItems":32,"uniqueItems":true,"items":{"$ref":"#/$defs/Ref"}},"gapCodes":{"$ref":"#/$defs/Codes"},"requested":{"type":"integer","minimum":0},"actual":{"type":"integer","minimum":0}}}}},
40
+ "Result":{"type":"object","additionalProperties":false,"required":["outcome","hardCriteriaMet","factRefs","gapCodes","blockers","relaxationsApplied"],"properties":{"outcome":{"enum":["complete","partial","empty"]},"requestedCount":{"type":"integer","minimum":0},"actualCount":{"type":"integer","minimum":0},"hardCriteriaMet":{"type":"boolean"},"factRefs":{"type":"array","maxItems":64,"uniqueItems":true,"items":{"$ref":"#/$defs/Ref"}},"gapCodes":{"$ref":"#/$defs/Codes"},"blockers":{"type":"array","maxItems":8,"items":{"$ref":"#/$defs/Blocker"}},"relaxationsApplied":{"type":"array","maxItems":1,"items":{"$ref":"#/$defs/Approval"}}}},
41
+ "Observation":{"oneOf":[{"type":"object","additionalProperties":false,"required":["kind"],"properties":{"kind":{"const":"search.state"},"searchSessionRef":{"$ref":"#/$defs/Ref"},"resultCount":{"type":"integer","minimum":0},"gapCodes":{"$ref":"#/$defs/Codes"}}},{"type":"object","additionalProperties":false,"required":["kind","matchedHotelRefs","visibleCount"],"properties":{"kind":{"const":"results.state"},"matchedHotelRefs":{"type":"array","maxItems":100,"items":{"$ref":"#/$defs/Ref"}},"visibleCount":{"type":"integer","minimum":0},"gapCodes":{"$ref":"#/$defs/Codes"}}},{"type":"object","additionalProperties":false,"required":["kind","hotelRef"],"properties":{"kind":{"enum":["hotel.focus","hotel.selection"]},"hotelRef":{"$ref":"#/$defs/Ref"}}},{"type":"object","additionalProperties":false,"required":["kind","hotelRefs","offerRefs","loadedHotelCount"],"properties":{"kind":{"const":"offers.state"},"hotelRefs":{"type":"array","maxItems":100,"items":{"$ref":"#/$defs/Ref"}},"offerRefs":{"type":"array","maxItems":200,"items":{"$ref":"#/$defs/Ref"}},"loadedHotelCount":{"type":"integer","minimum":0},"gapCodes":{"$ref":"#/$defs/Codes"}}},{"type":"object","additionalProperties":false,"required":["kind","offerRef","checkedOfferVersionRef","available","changedFactRefs"],"properties":{"kind":{"const":"offer.availability"},"offerRef":{"$ref":"#/$defs/Ref"},"checkedOfferVersionRef":{"$ref":"#/$defs/Ref"},"currentOfferVersionRef":{"$ref":"#/$defs/Ref"},"verifiedOfferRef":{"$ref":"#/$defs/Ref"},"available":{"type":"boolean"},"changedFactRefs":{"type":"array","maxItems":64,"items":{"$ref":"#/$defs/Ref"}},"gapCodes":{"$ref":"#/$defs/Codes"}}},{"type":"object","additionalProperties":false,"required":["kind","code","factRefs"],"properties":{"kind":{"const":"gap"},"code":{"enum":["byos_mapped_risk","check_avail_failed","check_avail_unverified","component_executor_unavailable","hotel_not_visible","hotel_rates_failed","offer_facts_changed","offer_not_loaded","offer_unavailable","order_not_found","order_outcome_not_observed","order_state_unknown","order_status_unavailable","requested_offers_not_loaded","search_failed","search_form_invalid","search_session_expired","search_terminal_timeout","stale_revision","surface_adapter_failed","undo_token_not_found","unhandled","unsupported","verified_offer_required","workspace_changed_during_action","criterion_must_not_met","no_hotels_matched","offer_target_not_reached"]},"factRefs":{"type":"array","maxItems":64,"items":{"$ref":"#/$defs/Ref"}}}}]},
42
+ "OfferSelectionObservation":{"type":"object","additionalProperties":false,"required":["kind","offerRef","offerVersionRef"],"properties":{"kind":{"const":"offer.selection"},"offerRef":{"$ref":"#/$defs/Ref"},"offerVersionRef":{"$ref":"#/$defs/Ref"}}},
43
+ "HandoffObservation":{"type":"object","additionalProperties":false,"required":["kind","offerRef","offerVersionRef","verifiedOfferRef","handoffRef"],"properties":{"kind":{"const":"checkout.handoff"},"offerRef":{"$ref":"#/$defs/Ref"},"offerVersionRef":{"$ref":"#/$defs/Ref"},"verifiedOfferRef":{"$ref":"#/$defs/Ref"},"handoffRef":{"$ref":"#/$defs/Ref"}}},
44
+ "OrderObservation":{"type":"object","additionalProperties":false,"required":["kind","orderRef","state"],"properties":{"kind":{"const":"order.state"},"orderRef":{"$ref":"#/$defs/Ref"},"state":{"enum":["pending","verified","failed","unknown"]},"gapCodes":{"$ref":"#/$defs/Codes"}}},
45
+ "ObservationExpanded":{"oneOf":[{"$ref":"#/$defs/Observation"},{"$ref":"#/$defs/OfferSelectionObservation"},{"$ref":"#/$defs/HandoffObservation"},{"$ref":"#/$defs/OrderObservation"}]},
46
+ "Receipt":{"type":"object","additionalProperties":false,"required":["schemaVersion","kind","actionId","contextRef","status","revision","observation","resultContract"],"properties":{"schemaVersion":{"const":"booking.surface.v2"},"kind":{"const":"action.receipt"},"actionId":{"$ref":"#/$defs/Ref"},"contextRef":{"$ref":"#/$defs/Ref"},"status":{"enum":["applied","needs_input","partial","no_match","unavailable","changed","stale","unsupported","failed"]},"revision":{"type":"integer","minimum":0},"observation":{"$ref":"#/$defs/ObservationExpanded"},"resultContract":{"$ref":"#/$defs/Result"},"undoToken":{"$ref":"#/$defs/Ref"}}},
47
+ "Ingress":{"type":"object","additionalProperties":false,"required":["schemaVersion","kind","requestKey","surfaceHint","workspace","request"],"properties":{"schemaVersion":{"const":"booking.surface.v2"},"kind":{"const":"user.turn.ingress"},"requestKey":{"$ref":"#/$defs/RequestKey"},"taskHandle":{"$ref":"#/$defs/Ref"},"surfaceHint":{"$ref":"#/$defs/Surface"},"workspace":{"$ref":"#/$defs/IngressWorkspace"},"request":{"type":"object","additionalProperties":false,"required":["text"],"properties":{"text":{"type":"string","minLength":1,"maxLength":4000}}}}},
48
+ "UserTurn":{"type":"object","additionalProperties":false,"required":["schemaVersion","kind","taskId","turnId","workspace","request"],"properties":{"schemaVersion":{"const":"booking.surface.v2"},"kind":{"const":"user.turn"},"taskId":{"$ref":"#/$defs/Ref"},"turnId":{"$ref":"#/$defs/Ref"},"workspace":{"$ref":"#/$defs/Workspace"},"request":{"type":"object","additionalProperties":false,"required":["text"],"properties":{"text":{"type":"string","minLength":1,"maxLength":4000},"approval":{"$ref":"#/$defs/Approval"}}}}},
49
+ "Continuation":{"type":"object","additionalProperties":false,"required":["schemaVersion","kind","taskId","workspace","receipt"],"properties":{"schemaVersion":{"const":"booking.surface.v2"},"kind":{"const":"action.receipt.continuation"},"taskId":{"$ref":"#/$defs/Ref"},"workspace":{"$ref":"#/$defs/Workspace"},"receipt":{"$ref":"#/$defs/Receipt"}}},
50
+ "Event":{"oneOf":[
51
+ {"$ref":"#/$defs/StatusEvent"},{"$ref":"#/$defs/QuestionEvent"},{"$ref":"#/$defs/OperationEvent"},{"$ref":"#/$defs/ExplanationEvent"},{"$ref":"#/$defs/TerminalEvent"},{"$ref":"#/$defs/ErrorEvent"}
52
+ ]},
53
+ "EventBase":{"type":"object","required":["schemaVersion","eventId","taskId","contextRef","sequence","emittedAt","kind"],"properties":{"schemaVersion":{"const":"booking.surface.v2"},"eventId":{"$ref":"#/$defs/Ref"},"taskId":{"$ref":"#/$defs/Ref"},"contextRef":{"$ref":"#/$defs/Ref"},"sequence":{"type":"integer","minimum":1},"emittedAt":{"type":"string","minLength":1},"kind":{"enum":["status","question","operation","explanation","terminal","error"]}}},
54
+ "StatusEvent":{"type":"object","allOf":[{"$ref":"#/$defs/EventBase"},{"type":"object","required":["kind","status"],"properties":{"kind":{"const":"status"},"status":{"enum":["submitted","working","waiting_receipt","input_required"]}}}],"unevaluatedProperties":false},
55
+ "QuestionEvent":{"type":"object","additionalProperties":false,"required":["schemaVersion","eventId","taskId","contextRef","sequence","emittedAt","kind","question"],"properties":{"schemaVersion":{"const":"booking.surface.v2"},"eventId":{"$ref":"#/$defs/Ref"},"taskId":{"$ref":"#/$defs/Ref"},"contextRef":{"$ref":"#/$defs/Ref"},"sequence":{"type":"integer","minimum":1},"emittedAt":{"type":"string","minLength":1},"kind":{"const":"question"},"question":{"type":"object","additionalProperties":false,"required":["questionId","prompt","missingFields","type","blocker","approvalOptions"],"properties":{"questionId":{"$ref":"#/$defs/Ref"},"prompt":{"type":"string","minLength":1},"missingFields":{"type":"array","maxItems":32,"items":{"type":"string"}},"type":{"const":"relaxation_approval_required"},"blocker":{"$ref":"#/$defs/Blocker"},"approvalOptions":{"type":"array","minItems":1,"maxItems":2,"items":{"type":"object","additionalProperties":false,"required":["approval"],"properties":{"approval":{"$ref":"#/$defs/Approval"}}}}}}}},
56
+ "OperationEvent":{"type":"object","allOf":[{"$ref":"#/$defs/EventBase"},{"type":"object","required":["kind","action"],"properties":{"kind":{"const":"operation"},"action":{"$ref":"#/$defs/Action"}}}],"unevaluatedProperties":false},
57
+ "ExplanationEvent":{"type":"object","allOf":[{"$ref":"#/$defs/EventBase"},{"type":"object","required":["kind","explanation"],"properties":{"kind":{"const":"explanation"},"explanation":{"type":"object","additionalProperties":false,"required":["text","factRefs"],"properties":{"text":{"type":"string","minLength":1},"factRefs":{"type":"array","maxItems":64,"items":{"$ref":"#/$defs/Ref"}}}}}}],"unevaluatedProperties":false},
58
+ "TerminalEvent":{"type":"object","allOf":[{"$ref":"#/$defs/EventBase"},{"type":"object","required":["kind","terminal"],"properties":{"kind":{"const":"terminal"},"terminal":{"type":"object","additionalProperties":false,"required":["status","summary","factRefs"],"properties":{"status":{"enum":["completed","stopped"]},"summary":{"type":"string","minLength":1},"factRefs":{"type":"array","maxItems":64,"items":{"$ref":"#/$defs/Ref"}}}}}}],"unevaluatedProperties":false},
59
+ "ErrorEvent":{"type":"object","allOf":[{"$ref":"#/$defs/EventBase"},{"type":"object","required":["kind","error"],"properties":{"kind":{"const":"error"},"error":{"type":"object","additionalProperties":false,"required":["code","message","retryable"],"properties":{"code":{"type":"string","pattern":"^[A-Z][A-Z0-9_.-]*$"},"message":{"type":"string","minLength":1},"retryable":{"type":"boolean"}}}}}],"unevaluatedProperties":false}
60
+ }
61
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * 可下单事实侧车持久化(issue #46,ADR-19):append-only JSONL 证据日志。
3
+ *
4
+ * 定位:这是**会话证据**而非用户状态——与 bridge-latency.jsonl / incidents.jsonl
5
+ * 同类(审计痕迹),不进账本投影。append-only 保历史(同 route+date 重查的旧快照
6
+ * 可回溯),读取侧经 dedupeFacts 取同 fact_id 最新。
7
+ *
8
+ * 路径:<stateRoot>/gotry-state/bookable-facts.jsonl
9
+ */
10
+
11
+ import { appendFile, mkdir, readFile } from 'node:fs/promises'
12
+ import { join } from 'node:path'
13
+ import { dedupeFacts, type BookableFact } from '../src/bookable-facts.ts'
14
+
15
+ export const FACT_LOG_NAME = 'bookable-facts.jsonl'
16
+
17
+ export function factLogPath(stateRoot: string): string {
18
+ const root = stateRoot === '.' ? process.cwd() : stateRoot
19
+ return join(root, 'gotry-state', FACT_LOG_NAME)
20
+ }
21
+
22
+ /** 追加事实(永不抛错:落盘失败不阻塞检索工具主路径,返回 false 由调用方记 incident) */
23
+ export async function appendFacts(stateRoot: string, facts: BookableFact[]): Promise<boolean> {
24
+ if (facts.length === 0) return true
25
+ try {
26
+ const p = factLogPath(stateRoot)
27
+ await mkdir(join(p, '..'), { recursive: true })
28
+ await appendFile(p, facts.map(f => JSON.stringify(f)).join('\n') + '\n', 'utf-8')
29
+ return true
30
+ } catch {
31
+ return false
32
+ }
33
+ }
34
+
35
+ /** 读注册表(去重后视图;无文件 = 空注册表,不抛) */
36
+ export async function loadFactRegistry(stateRoot: string): Promise<BookableFact[]> {
37
+ try {
38
+ const raw = await readFile(factLogPath(stateRoot), 'utf-8')
39
+ const facts: BookableFact[] = []
40
+ for (const line of raw.split('\n')) {
41
+ const t = line.trim()
42
+ if (!t) continue
43
+ try {
44
+ const f = JSON.parse(t) as BookableFact
45
+ if (f.schema === 'gotry_bookable_fact.v1' && f.fact_id) facts.push(f)
46
+ } catch {
47
+ // 单行损坏不拖垮整本注册表(与 incidents/latency 日志同纪律)
48
+ }
49
+ }
50
+ return dedupeFacts(facts)
51
+ } catch {
52
+ return []
53
+ }
54
+ }
@@ -15,6 +15,9 @@
15
15
  */
16
16
 
17
17
  import { spawn } from 'node:child_process'
18
+ import { closeSync, openSync, readFileSync, unlinkSync } from 'node:fs'
19
+ import { tmpdir } from 'node:os'
20
+ import { join } from 'node:path'
18
21
 
19
22
  export type FlyaiKind = 'flight' | 'train' | 'hotel'
20
23
 
@@ -175,20 +178,30 @@ export function parseFlyaiItemList(stdout: string): unknown[] {
175
178
  }
176
179
 
177
180
 
181
+ /**
182
+ * 子进程 stdout 走临时文件而非管道(issue #84):
183
+ * flyai CLI 异步写 stdout 后立即 process.exit();stdout 是管道时未 flush 的
184
+ * 尾部会被丢掉(实测截断在 ~7.6KB,exit=0 静默)。stdout 是文件时 Node 同步写,
185
+ * exit 不丢数据;且文件无 64KB 管道缓冲上限。close 后读文件,语义不变。
186
+ */
178
187
  function sh(cmd: string, args: string[], opts: { timeoutMs: number }) {
179
- const child = spawn(cmd, args, { env: process.env, cwd: process.cwd() })
180
- let stdout = ''
188
+ const outFile = join(tmpdir(), `gotry-flyai-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.out`)
189
+ const outFd = openSync(outFile, 'w')
190
+ const child = spawn(cmd, args, { env: process.env, cwd: process.cwd(), stdio: ['ignore', outFd, 'pipe'] })
181
191
  let stderr = ''
182
192
  let error: string | undefined
183
193
  const timer = setTimeout(() => {
184
194
  try { child.kill('SIGKILL') } catch { /* ignore */ }
185
195
  }, opts.timeoutMs)
186
196
  return new Promise<{ code: number; stdout: string; stderr: string; error?: string; timedOut?: boolean }>((resolve) => {
187
- child.stdout?.on('data', (d: Buffer) => { stdout += d.toString() })
188
197
  child.stderr?.on('data', (d: Buffer) => { stderr += d.toString() })
189
198
  child.on('error', (e) => { error = (e as Error).message.slice(0, 200) })
190
199
  child.on('close', (code) => {
191
200
  clearTimeout(timer)
201
+ closeSync(outFd)
202
+ let stdout = ''
203
+ try { stdout = readFileSync(outFile, 'utf8') } catch { /* 子进程未启动时文件可能为空,按空 stdout 处理 */ }
204
+ try { unlinkSync(outFile) } catch { /* ignore */ }
192
205
  resolve({ code: code ?? -1, stdout, stderr, error })
193
206
  })
194
207
  }).finally(() => clearTimeout(timer))
@@ -194,3 +194,49 @@ export async function listDestinations(opts: HbcliCallOptions = {}): Promise<Hbc
194
194
  const r = await callHbcliJson(['search', 'destinations', '--json'], opts)
195
195
  return { ...r, destinations: r.result }
196
196
  }
197
+
198
+ /**
199
+ * 高层语义化封装:房型报价(hotel-rates;上游 hotelRates 创建后端 session,
200
+ * 产出带 RatePkgId 的房型列表——check-avail 与 book 的入参来源)。
201
+ *
202
+ * 价格面无静态降级(fail-closed):hotel-list 的静态包降级是定性住宿信息,
203
+ * 房价是钱——估算价格冒充实时价是红线;不可用就诚实失败,证据链标注,
204
+ * 与 bookable-facts 证据分级(live_inventory 才可进确认卡)同口径。
205
+ */
206
+ export async function hotelRates(
207
+ query: {
208
+ hotelId: string
209
+ checkIn?: string
210
+ checkOut?: string
211
+ adults?: number
212
+ countryCode?: string
213
+ nationalityCode?: string
214
+ residencyCode?: string
215
+ },
216
+ opts: HbcliCallOptions = {},
217
+ ): Promise<HbcliCallResult & { rates?: unknown; summary: string }> {
218
+ const hbArgs = ['search', 'hotel-rates', '--json', '--hotel-id', query.hotelId]
219
+ if (query.checkIn) hbArgs.push('--check-in', query.checkIn)
220
+ if (query.checkOut) hbArgs.push('--check-out', query.checkOut)
221
+ if (query.countryCode) hbArgs.push('--country-code', query.countryCode)
222
+ if (query.nationalityCode) hbArgs.push('--nationality-code', query.nationalityCode)
223
+ if (query.residencyCode) hbArgs.push('--residency-code', query.residencyCode)
224
+ if (query.adults) hbArgs.push('--room-occupancies', JSON.stringify([{ adultCount: query.adults, childrenAges: [] }]))
225
+ const live = await callHbcliJson(hbArgs, opts)
226
+ const summary = live.via === 'hbcli-realtime'
227
+ ? `hotel ${query.hotelId}:hbcli 实时报价${query.checkIn ? `(${query.checkIn} → ${query.checkOut ?? '?'})` : ''}`
228
+ : `hotel ${query.hotelId}:hbcli 实时报价不可用(${live.error ?? live.via});价格面无静态降级,fail-closed 不估算`
229
+ return { ...live, rates: live.result, summary }
230
+ }
231
+
232
+ /** 高层语义化封装:下单前实时验价(check-avail;入参 RatePkgId 来自 hotel-rates 产物)。价格面同上:不可用即诚实失败。 */
233
+ export async function checkAvail(
234
+ query: { ratePkgId: string },
235
+ opts: HbcliCallOptions = {},
236
+ ): Promise<HbcliCallResult & { avail?: unknown; summary: string }> {
237
+ const live = await callHbcliJson(['search', 'check-avail', '--json', '--rate-pkg-id', query.ratePkgId], opts)
238
+ const summary = live.via === 'hbcli-realtime'
239
+ ? `ratePkg ${query.ratePkgId}:hbcli 实时验价(库存与价格以后端为准)`
240
+ : `ratePkg ${query.ratePkgId}:hbcli 实时验价不可用(${live.error ?? live.via});价格面无静态降级,fail-closed`
241
+ return { ...live, avail: live.result, summary }
242
+ }
@@ -4,7 +4,7 @@
4
4
  * 只处理已经脱敏、结构化的证据;不打开浏览器、不读登录态,也不执行任何写操作。
5
5
  */
6
6
 
7
- export type SessionEvidenceVerdict = 'hit' | 'miss' | 'error' | 'challenged' | 'cooldown' | 'needs-login' | 'needs-attach'
7
+ export type SessionEvidenceVerdict = 'hit' | 'miss' | 'error' | 'challenged' | 'cooldown' | 'needs-login' | 'needs-attach' | 'needs-extension'
8
8
 
9
9
  export const SESSION_BENCHMARK_SCHEMA_VERSION = 'session-double-source.v1' as const
10
10
  export const SESSION_FIELD_ACCURACY_THRESHOLD = 0.9
@@ -162,6 +162,7 @@ export type DoubleSourceState =
162
162
  | 'divergent'
163
163
  | 'waiting_attach'
164
164
  | 'waiting_login'
165
+ | 'waiting_extension'
165
166
  | 'challenge_stop'
166
167
  | 'guard_violation'
167
168
  | 'source_unavailable'
@@ -252,6 +253,8 @@ export function evaluateDoubleSource(input: {
252
253
  }
253
254
  if (!session) return baseEvaluation('source_unavailable', 'no_spend_stop')
254
255
  if (session.verdict === 'needs-attach') return baseEvaluation('waiting_attach', 'no_spend_waiting_user')
256
+ // 扩展车道(2026-08-29 PRIMARY 传输)未就绪:与 waiting-* 同族 no-spend,等待用户一次性安装
257
+ if (session.verdict === 'needs-extension') return baseEvaluation('waiting_extension', 'no_spend_waiting_user')
255
258
  if (session.verdict === 'needs-login') return baseEvaluation('waiting_login', 'no_spend_waiting_user')
256
259
  if (!official || official.verdict !== 'hit' || session.verdict !== 'hit') {
257
260
  return baseEvaluation('source_unavailable', 'no_spend_stop')