@danceiny/gotry 0.0.1-rc.8 → 0.2.0-rc.27

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 (506) hide show
  1. package/README.md +172 -217
  2. package/README.zh-CN.md +222 -0
  3. package/bin/gotry-backend.js +53 -0
  4. package/bin/gotry-booking-copilot.js +53 -0
  5. package/bin/gotry-bootstrap.js +1744 -0
  6. package/bin/gotry-inner.js +733 -83
  7. package/bin/gotry-process-liveness.d.ts +27 -0
  8. package/bin/gotry-process-liveness.js +97 -0
  9. package/bin/gotry-runtime-resolution.d.ts +27 -0
  10. package/bin/gotry-runtime-resolution.js +49 -0
  11. package/bin/gotry.js +1 -1
  12. package/client/client.js +203 -0
  13. package/cordis.gotry-patch.yml +80 -49
  14. package/data/airline-airports.json +39 -0
  15. package/data/stations-12306-verify.json +524 -0
  16. package/dist/capabilities/agent-reach-deep.js +45 -122
  17. package/dist/capabilities/agent-reach.js +101 -146
  18. package/dist/capabilities/anything.js +135 -94
  19. package/dist/capabilities/artifacts.js +370 -0
  20. package/dist/capabilities/channel-health.js +131 -0
  21. package/dist/capabilities/channel-registry.js +256 -0
  22. package/dist/capabilities/doctor.js +546 -0
  23. package/dist/capabilities/effect.js +394 -0
  24. package/dist/capabilities/external-event.js +149 -0
  25. package/dist/capabilities/fact-log.js +55 -0
  26. package/dist/capabilities/flyai-config.js +337 -0
  27. package/dist/capabilities/flyai.js +968 -0
  28. package/dist/capabilities/fx-contract.js +293 -0
  29. package/dist/capabilities/geo-atlas.js +246 -0
  30. package/dist/capabilities/ground-transfer.js +509 -0
  31. package/dist/capabilities/hbcli.js +260 -123
  32. package/dist/capabilities/hotelbyte-transaction.js +194 -0
  33. package/dist/capabilities/incident-log.js +131 -61
  34. package/dist/capabilities/itinerary-artifact.js +190 -0
  35. package/dist/capabilities/itinerary-deck-artifact.js +194 -0
  36. package/dist/capabilities/itinerary-deck-export.js +339 -0
  37. package/dist/capabilities/lavish-local.js +924 -0
  38. package/dist/capabilities/model-override.js +38 -0
  39. package/dist/capabilities/opensky.js +54 -43
  40. package/dist/capabilities/resilience.js +191 -0
  41. package/dist/capabilities/session/action-cache.js +126 -0
  42. package/dist/capabilities/session/adapters/ctrip-flight.js +141 -0
  43. package/dist/capabilities/session/adapters/ctrip-hotel.js +222 -0
  44. package/dist/capabilities/session/adapters/dida-portal.js +274 -0
  45. package/dist/capabilities/session/adapters/meituan-local.js +54 -0
  46. package/dist/capabilities/session/adapters/rail-12306.js +342 -0
  47. package/dist/capabilities/session/benchmark.js +189 -0
  48. package/dist/capabilities/session/bridge-ledger.js +224 -0
  49. package/dist/capabilities/session/extension-bridge.js +636 -0
  50. package/dist/capabilities/session/extension-channel.js +109 -0
  51. package/dist/capabilities/session/extension-distribution.js +230 -0
  52. package/dist/capabilities/session/extract.js +50 -0
  53. package/dist/capabilities/session/golden-score.js +114 -0
  54. package/dist/capabilities/session/health-watch.js +215 -0
  55. package/dist/capabilities/session/read-guard.js +107 -0
  56. package/dist/capabilities/session/static-flight-golden.js +150 -0
  57. package/dist/capabilities/session/transport.js +109 -0
  58. package/dist/capabilities/session/wizard.js +117 -0
  59. package/dist/capabilities/session-consent.js +178 -0
  60. package/dist/capabilities/session-login.js +170 -0
  61. package/dist/capabilities/session-search.js +686 -0
  62. package/dist/capabilities/spawn-bounded.js +203 -0
  63. package/dist/capabilities/sponsor-plugin.js +341 -0
  64. package/dist/capabilities/visa-policy.js +140 -0
  65. package/dist/capabilities/weather.js +243 -138
  66. package/dist/data/session-golden-20.json +25 -0
  67. package/dist/data/sf-golden-manifest.json +103 -0
  68. package/dist/data/sf-static-routes.json +91 -0
  69. package/dist/scripts/action-cache-tests.js +72 -0
  70. package/dist/scripts/agent-planning-turn-deadline-e2e.js +242 -0
  71. package/dist/scripts/agent-planning-turn-deadline-tests.js +185 -0
  72. package/dist/scripts/agent-reach-deep-tests.js +30 -40
  73. package/dist/scripts/agent-reach-error-tests.js +354 -0
  74. package/dist/scripts/agent-reach-tests.js +26 -18
  75. package/dist/scripts/agent-reach-wrapper-tests.js +50 -50
  76. package/dist/scripts/anything-tests.js +116 -60
  77. package/dist/scripts/artifact-client-contract-tests.js +220 -0
  78. package/dist/scripts/artifacts-capability-tests.js +727 -0
  79. package/dist/scripts/async-collect.js +68 -10
  80. package/dist/scripts/benchmark-environment-bridge-e2e.js +741 -0
  81. package/dist/scripts/benchmark-environment-bridge-tests.js +1452 -0
  82. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +126 -0
  83. package/dist/scripts/booking-copilot-availability-policy-tests.js +265 -0
  84. package/dist/scripts/booking-copilot-bin-proof-tests.js +66 -0
  85. package/dist/scripts/booking-copilot-cleanup-proof-helper.js +76 -0
  86. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +144 -0
  87. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +424 -0
  88. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +2839 -0
  89. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +309 -0
  90. package/dist/scripts/booking-copilot-dsh-readiness-proof.js +238 -0
  91. package/dist/scripts/booking-copilot-dsh-warmer-proof.js +123 -0
  92. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +156 -0
  93. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +70 -0
  94. package/dist/scripts/booking-copilot-intent-proof-tests.js +422 -0
  95. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +184 -0
  96. package/dist/scripts/booking-copilot-planner-live-probe.js +95 -0
  97. package/dist/scripts/booking-copilot-proof-runtime.js +42 -0
  98. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +210 -0
  99. package/dist/scripts/booking-copilot-runtime-proof-tests.js +2349 -0
  100. package/dist/scripts/booking-copilot-server-proof-tests.js +784 -0
  101. package/dist/scripts/booking-copilot-startup-proof-tests.js +94 -0
  102. package/dist/scripts/booking-executor-tests.js +80 -0
  103. package/dist/scripts/booking-recovery-chain-tests.js +182 -0
  104. package/dist/scripts/booking-saga-tests.js +125 -0
  105. package/dist/scripts/booking-surface-contract-proof-tests.js +212 -0
  106. package/dist/scripts/bootstrap-tests.js +1479 -0
  107. package/dist/scripts/bridge-events-tests.js +239 -0
  108. package/dist/scripts/bridge-ledger-tests.js +428 -0
  109. package/dist/scripts/build-changelog.js +238 -0
  110. package/dist/scripts/build-metrics-report.js +331 -0
  111. package/dist/scripts/changelog-tests.js +118 -0
  112. package/dist/scripts/channel-probe-tests.js +103 -0
  113. package/dist/scripts/channel-probe.js +169 -0
  114. package/dist/scripts/channel-registry-tests.js +208 -0
  115. package/dist/scripts/companion-tests.js +67 -0
  116. package/dist/scripts/dida-cookie-probe.js +87 -0
  117. package/dist/scripts/dida-runner-stop-tests.js +311 -0
  118. package/dist/scripts/dida-sw-probe.js +114 -0
  119. package/dist/scripts/diff-test.js +17 -12
  120. package/dist/scripts/doctor-tests.js +564 -0
  121. package/dist/scripts/dsh-artifact-e2e.js +279 -0
  122. package/dist/scripts/dsh-artifact-web-e2e.js +675 -0
  123. package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
  124. package/dist/scripts/dsh-runtime-closure-tests.js +182 -0
  125. package/dist/scripts/dsh-runtime-closure.js +162 -0
  126. package/dist/scripts/dsh-session-v3-migration-proof.js +109 -0
  127. package/dist/scripts/dsh-subprocess-local-proof.js +150 -0
  128. package/dist/scripts/dsh-target-closure-proof.js +178 -0
  129. package/dist/scripts/effect-tests.js +539 -0
  130. package/dist/scripts/engine-run.js +1 -3
  131. package/dist/scripts/engine-tests.js +16 -10
  132. package/dist/scripts/evaluation-cadence-tests.js +174 -0
  133. package/dist/scripts/evaluation-contract-tests.js +268 -0
  134. package/dist/scripts/extension-distribution-cli.js +39 -0
  135. package/dist/scripts/extension-distribution-tests.js +443 -0
  136. package/dist/scripts/extension-tests.js +988 -0
  137. package/dist/scripts/external-event-tests.js +350 -0
  138. package/dist/scripts/fact-gate-tests.js +869 -0
  139. package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
  140. package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
  141. package/dist/scripts/flight-malformed-tests.js +159 -0
  142. package/dist/scripts/flyai-setup-tests.js +228 -0
  143. package/dist/scripts/flyai-setup-tool-tests.js +54 -0
  144. package/dist/scripts/flyai-tests.js +692 -0
  145. package/dist/scripts/flyai-tool-registration-contract-tests.js +91 -0
  146. package/dist/scripts/fx-contract-tests.js +201 -0
  147. package/dist/scripts/g5-guard-tests.js +131 -0
  148. package/dist/scripts/g5-guard.js +189 -0
  149. package/dist/scripts/gen-lunar-anchors.js +106 -0
  150. package/dist/scripts/geo-atlas-tests.js +283 -0
  151. package/dist/scripts/gotry-backend-kernel-tests.js +206 -0
  152. package/dist/scripts/gotry-try-demo-tests.js +79 -0
  153. package/dist/scripts/gotry-try-demo.js +49 -0
  154. package/dist/scripts/ground-transfer-tests.js +956 -0
  155. package/dist/scripts/hbcli-e2e-tests.js +159 -0
  156. package/dist/scripts/hbcli-live-optin-tests.js +96 -0
  157. package/dist/scripts/hbcli-release-contract-tests.js +122 -0
  158. package/dist/scripts/hbcli-tests.js +121 -69
  159. package/dist/scripts/health-watch-cli.js +73 -0
  160. package/dist/scripts/hotel-date-gate-tests.js +496 -0
  161. package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
  162. package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
  163. package/dist/scripts/i18n-tests.js +41 -0
  164. package/dist/scripts/incident-tests.js +281 -87
  165. package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
  166. package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
  167. package/dist/scripts/issue-271-liveness-tests.js +569 -0
  168. package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
  169. package/dist/scripts/issue-289-model-retry-tests.js +441 -0
  170. package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
  171. package/dist/scripts/issue-338-home-city-e2e.js +577 -0
  172. package/dist/scripts/issue343-real-entry-e2e.js +160 -0
  173. package/dist/scripts/issue436-persisted-routing-e2e.js +247 -0
  174. package/dist/scripts/itinerary-artifact-tests.js +368 -0
  175. package/dist/scripts/itinerary-deck-artifact-tests.js +416 -0
  176. package/dist/scripts/itinerary-deck-export-tests.js +552 -0
  177. package/dist/scripts/itinerary-deck-tests.js +435 -0
  178. package/dist/scripts/itinerary-html-tests.js +426 -0
  179. package/dist/scripts/journey-tests.js +22 -27
  180. package/dist/scripts/kernel-manifest-evidence.js +109 -0
  181. package/dist/scripts/kernel-manifest-gate.js +126 -0
  182. package/dist/scripts/kernel-manifest-tests.js +212 -0
  183. package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
  184. package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
  185. package/dist/scripts/kernel-manifest.js +369 -0
  186. package/dist/scripts/lavish-local-tests.js +1226 -0
  187. package/dist/scripts/lavish-product-tools-tests.js +537 -0
  188. package/dist/scripts/ledger-repair-apply-tests.js +316 -0
  189. package/dist/scripts/ledger-repair-plan-tests.js +375 -0
  190. package/dist/scripts/ledger-tests.js +480 -0
  191. package/dist/scripts/ledger-workflow-crash.js +32 -0
  192. package/dist/scripts/managed-dsh-cleanup-diagnostic-proof.js +184 -0
  193. package/dist/scripts/managed-dsh-close-failure-proof.js +172 -0
  194. package/dist/scripts/managed-dsh-run-port-proof.js +153 -0
  195. package/dist/scripts/managed-dsh-terminal-proof.js +252 -0
  196. package/dist/scripts/map-tools-vendor-package-proof.js +365 -0
  197. package/dist/scripts/memory-capture-tests.js +242 -61
  198. package/dist/scripts/memory-decay-tests.js +49 -0
  199. package/dist/scripts/memory-lifecycle-tests.js +657 -0
  200. package/dist/scripts/memory-lifecycle.js +196 -0
  201. package/dist/scripts/memory-metrics.js +29 -31
  202. package/dist/scripts/memory-value-report.js +631 -0
  203. package/dist/scripts/memory-value-tests.js +328 -0
  204. package/dist/scripts/metrics-report-tests.js +151 -0
  205. package/dist/scripts/model-override-e2e.js +137 -0
  206. package/dist/scripts/nightly-evidence-tests.js +161 -0
  207. package/dist/scripts/nightly-evidence.js +286 -0
  208. package/dist/scripts/nudge-digest.js +43 -42
  209. package/dist/scripts/observability-tests.js +381 -0
  210. package/dist/scripts/onboarding-tests.js +161 -0
  211. package/dist/scripts/opensky-check.js +18 -13
  212. package/dist/scripts/opensky-tests.js +28 -28
  213. package/dist/scripts/persona-surface-guard-tests.js +49 -0
  214. package/dist/scripts/pnpm-dsh-closure-proof.js +17 -0
  215. package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
  216. package/dist/scripts/price-drift-tests.js +340 -0
  217. package/dist/scripts/price-drift-watch.js +447 -0
  218. package/dist/scripts/probe-poi-tests.js +53 -45
  219. package/dist/scripts/product-metrics.js +483 -0
  220. package/dist/scripts/publish-preverify.js +110 -0
  221. package/dist/scripts/realtime-pricing-tests.js +76 -0
  222. package/dist/scripts/recall-tests.js +513 -0
  223. package/dist/scripts/replay-async.js +20 -18
  224. package/dist/scripts/replay-real.js +18 -18
  225. package/dist/scripts/replay.js +52 -82
  226. package/dist/scripts/session-attach-diagnose.js +31 -0
  227. package/dist/scripts/session-attach-poc.js +62 -0
  228. package/dist/scripts/session-benchmark.js +180 -0
  229. package/dist/scripts/session-dida-live-e2e.js +199 -0
  230. package/dist/scripts/session-extract-tests.js +60 -0
  231. package/dist/scripts/session-link-tests.js +478 -0
  232. package/dist/scripts/session-login.js +29 -0
  233. package/dist/scripts/session-tests.js +862 -0
  234. package/dist/scripts/session-zones-tests.js +358 -0
  235. package/dist/scripts/sf-live-benchmark.js +367 -0
  236. package/dist/scripts/sf-live-challenge-stop-tests.js +453 -0
  237. package/dist/scripts/sf-live-cli-tests.js +92 -0
  238. package/dist/scripts/sf-live-options.js +46 -0
  239. package/dist/scripts/sf-manifest-tests.js +30 -0
  240. package/dist/scripts/sf-manifest.js +33 -0
  241. package/dist/scripts/sf-soft-score-tests.js +67 -0
  242. package/dist/scripts/sf-summary-tests.js +324 -0
  243. package/dist/scripts/sf-summary.js +525 -0
  244. package/dist/scripts/share-tests.js +432 -0
  245. package/dist/scripts/skeleton-check.js +16 -14
  246. package/dist/scripts/skeleton-integration-test.js +28 -11
  247. package/dist/scripts/skills-contract-tests.js +51 -46
  248. package/dist/scripts/smoke-session-gate-tests.js +21 -0
  249. package/dist/scripts/smoke.js +703 -219
  250. package/dist/scripts/spawn-bounded-abort-tests.js +241 -0
  251. package/dist/scripts/sponsor-reuse-tests.js +262 -0
  252. package/dist/scripts/state-cli-tests.js +261 -0
  253. package/dist/scripts/state-cli.js +585 -0
  254. package/dist/scripts/state-repair-cli.js +66 -0
  255. package/dist/scripts/state-repair-tests.js +140 -0
  256. package/dist/scripts/static-golden-tests.js +165 -0
  257. package/dist/scripts/time-eval-tests.js +210 -192
  258. package/dist/scripts/travel-timeline-tests.js +59 -0
  259. package/dist/scripts/turn-handoff-collect-tests.js +169 -0
  260. package/dist/scripts/turn-handoff-collect.js +161 -0
  261. package/dist/scripts/turn-policy-tests.js +55 -0
  262. package/dist/scripts/typed-contract-canary.js +176 -0
  263. package/dist/scripts/tz-resolver-sanity.js +50 -0
  264. package/dist/scripts/tz-resolver-tests.js +584 -0
  265. package/dist/scripts/unified-tests.js +23 -19
  266. package/dist/scripts/visa-policy-tests.js +62 -0
  267. package/dist/scripts/weather-tests.js +276 -41
  268. package/dist/scripts/wish-channel-gate-tests.js +54 -0
  269. package/dist/scripts/write-gate-tests.js +522 -0
  270. package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
  271. package/dist/scripts/z3-lifecycle-tests.js +170 -0
  272. package/dist/scripts/z3-race-repeat-tests.js +39 -0
  273. package/dist/scripts/z3-race-tests.js +41 -0
  274. package/dist/src/artifact-gate.js +829 -0
  275. package/dist/src/backend/kernel.js +91 -0
  276. package/dist/src/backend/modules/booking-copilot.js +92 -0
  277. package/dist/src/backend/modules/booking-executor.js +124 -0
  278. package/dist/src/backend/modules/session-search.js +551 -0
  279. package/dist/src/benchmark-agent-conformance.js +578 -0
  280. package/dist/src/benchmark-environment-bridge.js +515 -0
  281. package/dist/src/benchmark-headless-child-diagnostics.js +166 -0
  282. package/dist/src/benchmark-tool-isolation.js +151 -0
  283. package/dist/src/bookable-facts.js +533 -0
  284. package/dist/src/booking-saga.js +97 -0
  285. package/dist/src/booking-surface/availability-policy.js +697 -0
  286. package/dist/src/booking-surface/booking-intent.js +43 -0
  287. package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
  288. package/dist/src/booking-surface/canonical-schema.js +116 -0
  289. package/dist/src/booking-surface/contracts.js +75 -0
  290. package/dist/src/booking-surface/dsh-planner.js +1854 -0
  291. package/dist/src/booking-surface/dsh-plugin.js +378 -0
  292. package/dist/src/booking-surface/dsh-worker.js +98 -0
  293. package/dist/src/booking-surface/error-codes.js +231 -0
  294. package/dist/src/booking-surface/index.js +9 -0
  295. package/dist/src/booking-surface/managed-dsh-cleanup-diagnostic.js +97 -0
  296. package/dist/src/booking-surface/managed-dsh-run-port.js +244 -0
  297. package/dist/src/booking-surface/profile.js +24 -0
  298. package/dist/src/booking-surface/recovery-chain.js +367 -0
  299. package/dist/src/booking-surface/runtime.js +1968 -0
  300. package/dist/src/booking-surface/server.js +674 -0
  301. package/dist/src/booking-surface/startup.js +168 -0
  302. package/dist/src/booking-surface/validation.js +261 -0
  303. package/dist/src/bridge.js +20 -13
  304. package/dist/src/companions.js +86 -0
  305. package/dist/src/contracts.js +21 -43
  306. package/dist/src/dsh-llm.js +97 -111
  307. package/dist/src/engine.js +276 -193
  308. package/dist/src/evaluation-cadence.js +97 -0
  309. package/dist/src/evaluation-contracts.js +283 -0
  310. package/dist/src/flight-pack-adapter.js +54 -0
  311. package/dist/src/flight-pack-contract.js +2 -0
  312. package/dist/src/flyai-setup-tool.js +70 -0
  313. package/dist/src/gotry-backend.js +125 -0
  314. package/dist/src/hotel-date-gate.js +118 -0
  315. package/dist/src/i18n.js +88 -0
  316. package/dist/src/index.js +2305 -731
  317. package/dist/src/itinerary-deck.js +139 -0
  318. package/dist/src/itinerary-doc-shared.js +661 -0
  319. package/dist/src/itinerary-html.js +131 -0
  320. package/dist/src/journey.js +155 -108
  321. package/dist/src/lavish-tools.js +400 -0
  322. package/dist/src/ledger-repair-apply.js +538 -0
  323. package/dist/src/ledger-repair-plan.js +463 -0
  324. package/dist/src/loop.js +358 -162
  325. package/dist/src/memory-capture.js +180 -32
  326. package/dist/src/memory-decay.js +47 -0
  327. package/dist/src/memory-lifecycle.js +1310 -0
  328. package/dist/src/memory-utility.js +27 -40
  329. package/dist/src/mock-llm.js +36 -61
  330. package/dist/src/model.js +81 -36
  331. package/dist/src/realtime-pricing.js +103 -0
  332. package/dist/src/recall/card.js +74 -0
  333. package/dist/src/recall/evaluator.js +140 -0
  334. package/dist/src/recall/integration.js +17 -0
  335. package/dist/src/recall/tick.js +166 -0
  336. package/dist/src/session-link/plan-it-action.js +48 -0
  337. package/dist/src/session-link/session-link.js +248 -0
  338. package/dist/src/session-zones.js +507 -0
  339. package/dist/src/share/adapters.js +51 -0
  340. package/dist/src/share/share-consent.js +76 -0
  341. package/dist/src/share/share-deck.js +58 -0
  342. package/dist/src/share/share-token.js +146 -0
  343. package/dist/src/slot-spec.js +84 -106
  344. package/dist/src/state-ledger.js +767 -0
  345. package/dist/src/state-repair.js +299 -0
  346. package/dist/src/subagent-job-id-guard.js +58 -0
  347. package/dist/src/time-anchor.js +231 -33
  348. package/dist/src/tool-packet.js +20 -8
  349. package/dist/src/travel-slots.js +58 -35
  350. package/dist/src/travel-timeline.js +59 -0
  351. package/dist/src/turn-deadline.js +287 -0
  352. package/dist/src/turn-policy.js +118 -0
  353. package/dist/src/tz-resolver.js +143 -0
  354. package/dist/src/unified.js +538 -360
  355. package/dist/src/wish-pool.js +42 -12
  356. package/dist/src/write-gate.js +495 -0
  357. package/dist/src/z3-shared.js +284 -0
  358. package/extension/README.md +21 -0
  359. package/extension/README.zh-CN.md +21 -0
  360. package/extension/background.js +463 -0
  361. package/extension/content-bridge.js +270 -0
  362. package/extension/content-main.js +111 -0
  363. package/extension/manifest.json +60 -0
  364. package/package.json +407 -14
  365. package/schemas/booking.intent.schema.json +193 -0
  366. package/schemas/booking.surface.schema.json +2622 -0
  367. package/ts/capabilities/agent-reach-deep.ts +114 -0
  368. package/ts/capabilities/agent-reach.ts +198 -0
  369. package/ts/capabilities/anything.ts +255 -0
  370. package/ts/capabilities/artifacts.ts +428 -0
  371. package/ts/capabilities/fact-log.ts +54 -0
  372. package/ts/capabilities/flyai-config.ts +388 -0
  373. package/ts/capabilities/flyai.ts +1274 -0
  374. package/ts/capabilities/hbcli.ts +253 -71
  375. package/ts/capabilities/incident-log.ts +88 -59
  376. package/ts/capabilities/itinerary-artifact.ts +214 -0
  377. package/ts/capabilities/itinerary-deck-artifact.ts +218 -0
  378. package/ts/capabilities/itinerary-deck-export.ts +378 -0
  379. package/ts/capabilities/opensky.ts +121 -0
  380. package/ts/capabilities/session/action-cache.ts +148 -0
  381. package/ts/capabilities/session/adapters/ctrip-flight.ts +181 -0
  382. package/ts/capabilities/session/adapters/ctrip-hotel.ts +238 -0
  383. package/ts/capabilities/session/adapters/dida-portal.ts +338 -0
  384. package/ts/capabilities/session/adapters/meituan-local.ts +70 -0
  385. package/ts/capabilities/session/adapters/rail-12306.ts +392 -0
  386. package/ts/capabilities/session/benchmark.ts +276 -0
  387. package/ts/capabilities/session/bridge-ledger.ts +333 -0
  388. package/ts/capabilities/session/extension-bridge.ts +794 -0
  389. package/ts/capabilities/session/extension-channel.ts +144 -0
  390. package/ts/capabilities/session/extension-distribution.ts +266 -0
  391. package/ts/capabilities/session/extract.ts +54 -0
  392. package/ts/capabilities/session/golden-score.ts +139 -0
  393. package/ts/capabilities/session/health-watch.ts +264 -0
  394. package/ts/capabilities/session/read-guard.ts +141 -0
  395. package/ts/capabilities/session/static-flight-golden.ts +209 -0
  396. package/ts/capabilities/session/transport.ts +146 -0
  397. package/ts/capabilities/session/wizard.ts +140 -0
  398. package/ts/capabilities/session-consent.ts +211 -0
  399. package/ts/capabilities/session-login.ts +208 -0
  400. package/ts/capabilities/session-search.ts +893 -0
  401. package/ts/capabilities/weather.ts +330 -0
  402. package/ts/dsh-runtime/vendor/README.md +68 -0
  403. package/ts/dsh-runtime/vendor/dsh-map-tools/LICENSE +21 -0
  404. package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +405 -0
  405. package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +404 -0
  406. package/ts/dsh-runtime/vendor/dsh-map-tools/client/client.js +1584 -0
  407. package/ts/dsh-runtime/vendor/dsh-map-tools/cordis.patch.yml +5 -0
  408. package/ts/dsh-runtime/vendor/dsh-map-tools/icon.svg +5 -0
  409. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/amap.js +595 -0
  410. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/nominatim.js +63 -0
  411. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/osrm.js +58 -0
  412. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/photon.js +55 -0
  413. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-file.js +87 -0
  414. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-route.js +131 -0
  415. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config.js +16 -0
  416. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/geo.js +232 -0
  417. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js +120 -0
  418. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +40 -0
  419. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/staticmap-route.js +115 -0
  420. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/geocode.js +127 -0
  421. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/poi.js +84 -0
  422. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/routes.js +267 -0
  423. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/amap.d.ts +90 -0
  424. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/nominatim.d.ts +17 -0
  425. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/osrm.d.ts +15 -0
  426. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/photon.d.ts +22 -0
  427. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-file.d.ts +33 -0
  428. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-route.d.ts +23 -0
  429. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config.d.ts +23 -0
  430. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/geo.d.ts +61 -0
  431. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/index.d.ts +18 -0
  432. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +14 -0
  433. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/staticmap-route.d.ts +31 -0
  434. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/geocode.d.ts +11 -0
  435. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/poi.d.ts +9 -0
  436. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/routes.d.ts +75 -0
  437. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/types.d.ts +68 -0
  438. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types.js +16 -0
  439. package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +97 -0
  440. package/ts/package.json +296 -3
  441. package/ts/scripts/async-collect.ts +91 -0
  442. package/ts/scripts/map-tools-vendor-package-proof.ts +404 -0
  443. package/ts/scripts/skeleton-check.ts +1 -1
  444. package/ts/scripts/skeleton-integration-test.ts +23 -1
  445. package/ts/scripts/state-cli.ts +568 -0
  446. package/ts/scripts/turn-handoff-collect.ts +178 -0
  447. package/ts/src/artifact-gate.ts +991 -0
  448. package/ts/src/benchmark-agent-conformance.ts +619 -0
  449. package/ts/src/benchmark-environment-bridge.ts +538 -0
  450. package/ts/src/benchmark-headless-child-diagnostics.ts +184 -0
  451. package/ts/src/benchmark-tool-isolation.ts +166 -0
  452. package/ts/src/bookable-facts.ts +837 -0
  453. package/ts/src/booking-saga.ts +133 -0
  454. package/ts/src/booking-surface/availability-policy.ts +522 -0
  455. package/ts/src/booking-surface/booking-intent.ts +86 -0
  456. package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
  457. package/ts/src/booking-surface/canonical-schema.js +116 -0
  458. package/ts/src/booking-surface/contracts.ts +475 -0
  459. package/ts/src/booking-surface/dsh-planner.ts +1949 -0
  460. package/ts/src/booking-surface/dsh-plugin.js +378 -0
  461. package/ts/src/booking-surface/dsh-worker.ts +110 -0
  462. package/ts/src/booking-surface/error-codes.ts +241 -0
  463. package/ts/src/booking-surface/index.ts +9 -0
  464. package/ts/src/booking-surface/managed-dsh-cleanup-diagnostic.ts +151 -0
  465. package/ts/src/booking-surface/managed-dsh-run-port.ts +273 -0
  466. package/ts/src/booking-surface/profile.ts +42 -0
  467. package/ts/src/booking-surface/recovery-chain.ts +409 -0
  468. package/ts/src/booking-surface/runtime.ts +1793 -0
  469. package/ts/src/booking-surface/server.ts +733 -0
  470. package/ts/src/booking-surface/startup.ts +201 -0
  471. package/ts/src/booking-surface/validation.ts +217 -0
  472. package/ts/src/companions.ts +113 -0
  473. package/ts/src/contracts.ts +13 -3
  474. package/ts/src/dsh-llm.ts +44 -11
  475. package/ts/src/flyai-setup-tool.ts +77 -0
  476. package/ts/src/index.ts +2107 -224
  477. package/ts/src/itinerary-deck.ts +189 -0
  478. package/ts/src/itinerary-doc-shared.ts +741 -0
  479. package/ts/src/itinerary-html.ts +171 -0
  480. package/ts/src/loop.ts +278 -40
  481. package/ts/src/memory-capture.ts +283 -0
  482. package/ts/src/memory-decay.ts +55 -0
  483. package/ts/src/memory-utility.ts +70 -0
  484. package/ts/src/mock-llm.ts +4 -8
  485. package/ts/src/model.ts +88 -2
  486. package/ts/src/recall/card.ts +106 -0
  487. package/ts/src/recall/evaluator.ts +170 -0
  488. package/ts/src/recall/integration.ts +35 -0
  489. package/ts/src/recall/tick.ts +213 -0
  490. package/ts/src/session-link/plan-it-action.ts +78 -0
  491. package/ts/src/session-link/session-link.ts +275 -0
  492. package/ts/src/share/adapters.ts +93 -0
  493. package/ts/src/share/share-consent.ts +105 -0
  494. package/ts/src/share/share-deck.ts +85 -0
  495. package/ts/src/share/share-token.ts +166 -0
  496. package/ts/src/slot-spec.ts +172 -0
  497. package/ts/src/state-ledger.ts +912 -0
  498. package/ts/src/subagent-job-id-guard.ts +72 -0
  499. package/ts/src/time-anchor.ts +338 -0
  500. package/ts/src/tool-packet.ts +32 -0
  501. package/ts/src/travel-slots.ts +219 -0
  502. package/ts/src/travel-timeline.ts +83 -0
  503. package/ts/src/turn-deadline.ts +366 -0
  504. package/ts/src/turn-policy.ts +154 -0
  505. package/ts/src/unified.ts +360 -89
  506. package/ts/src/wish-pool.ts +79 -0
@@ -0,0 +1,42 @@
1
+ import type { BookingReadActionKind } from './contracts.ts'
2
+
3
+ export const EMBEDDED_BOOKING_CAPABILITY_IDS = [
4
+ 'search-hotels',
5
+ 'refine-results',
6
+ 'find-room-offers',
7
+ 'compare-offers',
8
+ 'prepare-booking',
9
+ 'observe-booking',
10
+ ] as const
11
+
12
+ export type EmbeddedBookingCapabilityId = (typeof EMBEDDED_BOOKING_CAPABILITY_IDS)[number]
13
+
14
+ export interface EmbeddedBookingCapability {
15
+ id: EmbeddedBookingCapabilityId
16
+ effect: 'read'
17
+ actions: readonly BookingReadActionKind[]
18
+ }
19
+
20
+ export interface EmbeddedBookingProfile {
21
+ id: 'embedded-booking'
22
+ schemaVersion: 'booking.surface'
23
+ capabilities: readonly EmbeddedBookingCapability[]
24
+ }
25
+
26
+ /** Closed registry. No booking/payment/write capability exists in this profile. */
27
+ export const embeddedBookingProfile = Object.freeze({
28
+ id: 'embedded-booking',
29
+ schemaVersion: 'booking.surface',
30
+ capabilities: Object.freeze([
31
+ Object.freeze({ id: 'search-hotels', effect: 'read', actions: Object.freeze(['search.patch', 'search.run']) }),
32
+ Object.freeze({ id: 'refine-results', effect: 'read', actions: Object.freeze(['results.view.patch', 'hotel.focus', 'hotel.select']) }),
33
+ Object.freeze({ id: 'find-room-offers', effect: 'read', actions: Object.freeze(['offers.query', 'offers.view.patch']) }),
34
+ Object.freeze({ id: 'compare-offers', effect: 'read', actions: Object.freeze(['offers.compare', 'offer.select']) }),
35
+ Object.freeze({ id: 'prepare-booking', effect: 'read', actions: Object.freeze(['offer.check', 'checkout.prepare']) }),
36
+ Object.freeze({ id: 'observe-booking', effect: 'read', actions: Object.freeze(['order.observe']) }),
37
+ ]),
38
+ }) as EmbeddedBookingProfile
39
+
40
+ export function actionsForEmbeddedCapability(id: EmbeddedBookingCapabilityId): readonly BookingReadActionKind[] {
41
+ return embeddedBookingProfile.capabilities.find((capability) => capability.id === id)?.actions ?? []
42
+ }
@@ -0,0 +1,409 @@
1
+ /**
2
+ * Booking Copilot unavailable/changed 恢复链契约层(issue #142 非门控切片)。
3
+ *
4
+ * ⚠ 非运行时激活:纯函数契约层,不发起供应商调用、不读凭据、不接线 runtime seam——
5
+ * #142 合并 gate 中「四 surface 真实库存」与「真实 Checkout/QueryOrders 证据」仍是
6
+ * no-spend 门控项(等真实供应商/UAT)。本层只把恢复链的**结构化处置**固化为可离线
7
+ * 证明的契约:检测(识别分类)→ 恢复(受控重试)→ 用户沟通(显式披露)→ 审计(可对账)。
8
+ * 检测/恢复的合法性判定仍归 availability reducer(ADR-23 availability-policy.ts)所有;
9
+ * 本层是它的用户沟通与审计投影,不替代、不绕过。
10
+ *
11
+ * 词汇复用(不发明新通道):
12
+ * - 分类闭集复用 ActionReceipt.status 闭集(changed/unavailable/no_match/applied/partial/
13
+ * stale/failed/needs_input/unsupported,contracts.ts)与 offer.availability/gap 观测形态;
14
+ * - 每酒店有界恢复预算复用 availability-policy 的 MAX_OFFER_QUERIES_PER_HOTEL /
15
+ * MAX_OFFER_CHECKS_PER_HOTEL(RECOVERY_REUSED_BUDGETS 冻结引用,防两处漂移);
16
+ * - 恢复轮次的模型调用语义对齐 planner 三次调用预算(dsh-planner attempt < 3):
17
+ * 每个触发源最多 3 次计入预算的恢复轮,第 4 次结构性拒绝、必须降级;
18
+ * - 审计事件命名沿用账本 booking.copilot.* 命名空间(runtime.ts 事件 kind 惯例);
19
+ * 链校验形态对齐 booking-saga 的 sagaTraceViolations(开立→推进→终态吸收)。
20
+ *
21
+ * 红线(全部结构性编码):
22
+ * - changed/unavailable 必须显式分类——不静默当确认,也不静默丢弃;
23
+ * - 不可确认证据只产生 inconclusive,不得宣称「市场无房」(与 availability reducer 同红线);
24
+ * - 恢复命中与用户原选择不同酒店/报价 = 替换,必须先出显式披露——静默换房换航结构性拒绝;
25
+ * - 恢复耗尽只能显式降级并向用户披露,不得静默替换或假称确认;
26
+ * - 版本位移(v1→v2)的解决必须携带非空变化说明——不静默换版;
27
+ * - 每条审计事件带 receiptDigest 可回溯;resolved/degraded 为吸收终态,其后不得再有事件;
28
+ * - 纯函数:每次推进返回新状态,原状态不可变。
29
+ */
30
+
31
+ import { createHash } from 'node:crypto'
32
+ import type { ActionReceipt } from './contracts.ts'
33
+ import { MAX_OFFER_CHECKS_PER_HOTEL, MAX_OFFER_QUERIES_PER_HOTEL } from './availability-policy.ts'
34
+
35
+ export const RECOVERY_CHAIN_SCHEMA = 'booking_recovery_chain.v1'
36
+
37
+ /** 每个触发源最多 3 次计入预算的恢复轮——对齐 planner 三次调用预算的语义(dsh-planner attempt < 3)。 */
38
+ export const MAX_RECOVERY_MODEL_TURNS_PER_TRIGGER = 3
39
+ export const MAX_RECOVERY_BUDGET_NOTE =
40
+ '3 counted model turns per trigger, aligned with the planner three-call attempt budget (dsh-planner); ' +
41
+ 'per-hotel query/check budgets stay policy-owned (availability-policy MAX_OFFER_QUERIES_PER_HOTEL / MAX_OFFER_CHECKS_PER_HOTEL)'
42
+
43
+ /** 恢复重试计入的既有预算(冻结引用 availability-policy 常量,防两处漂移)。 */
44
+ export const RECOVERY_REUSED_BUDGETS = {
45
+ offerQueriesPerHotel: MAX_OFFER_QUERIES_PER_HOTEL,
46
+ offerChecksPerHotel: MAX_OFFER_CHECKS_PER_HOTEL,
47
+ modelTurnsPerTrigger: MAX_RECOVERY_MODEL_TURNS_PER_TRIGGER,
48
+ } as const
49
+
50
+ /** 检测分类(闭集;与 ActionReceipt.status 词汇一一对应,不发明新通道)。 */
51
+ export type RecoveryClassification =
52
+ | { kind: 'confirmed'; offerRef: string; offerVersionRef: string; verifiedOfferRef: string }
53
+ | { kind: 'changed'; offerRef: string; checkedOfferVersionRef: string; currentOfferVersionRef?: string; changedFactRefs: string[]; reason: string }
54
+ | { kind: 'unavailable'; offerRef: string; offerVersionRef: string; reason: string }
55
+ | { kind: 'inconclusive'; reason: string }
56
+ | { kind: 'unrelated'; observationKind: ActionReceipt['observation']['kind']; reason: string }
57
+
58
+ export type RecoveryChainPhase = 'detected' | 'recovering' | 'resolved' | 'degraded'
59
+
60
+ /** 受控恢复的路径闭集:换版重查 / 同酒店重查 / 替代候选——恢复不开新的无界重试通道。 */
61
+ export type RecoveryApproach = 'recheck_version' | 'requery_same_hotel' | 'alternative_candidate'
62
+ const RECOVERY_APPROACHES: ReadonlySet<string> = new Set(['recheck_version', 'requery_same_hotel', 'alternative_candidate'])
63
+
64
+ export interface RecoverySelectionRef { hotelRef: string; offerRef: string; offerVersionRef: string }
65
+
66
+ export type RecoveryAuditEventKind =
67
+ | 'recovery.detected'
68
+ | 'recovery.attempt'
69
+ | 'recovery.disclosed'
70
+ | 'recovery.resolved'
71
+ | 'recovery.degraded'
72
+
73
+ /** 审计事件(账本 booking.copilot.* 命名空间惯例;receiptDigest 证据链,不落敏感原值)。 */
74
+ export interface RecoveryAuditEvent {
75
+ at: string
76
+ kind: RecoveryAuditEventKind
77
+ from: RecoveryChainPhase
78
+ to: RecoveryChainPhase
79
+ reason: string
80
+ /** sha256(分类输入 receipt 的规范 JSON)——可回溯原始凭证 */
81
+ receiptDigest?: string
82
+ target?: RecoverySelectionRef
83
+ substitution?: boolean
84
+ }
85
+
86
+ export interface RecoveryChainState {
87
+ readonly schemaVersion: typeof RECOVERY_CHAIN_SCHEMA
88
+ readonly taskId: string
89
+ readonly contextRef: string
90
+ readonly trigger: 'changed' | 'unavailable' | 'inconclusive'
91
+ readonly triggerReason: string
92
+ /** 用户原选择:替换判定的不变基线 */
93
+ readonly originalSelection: RecoverySelectionRef
94
+ readonly countedModelTurns: number
95
+ readonly phase: RecoveryChainPhase
96
+ readonly substitutionDisclosed: boolean
97
+ readonly resolvedTo?: RecoverySelectionRef
98
+ readonly history: readonly RecoveryAuditEvent[]
99
+ }
100
+
101
+ function isNonEmpty(value: unknown): value is string { return typeof value === 'string' && value.trim().length > 0 }
102
+ function requireBinding(key: string, value: unknown): string {
103
+ if (!isNonEmpty(value)) throw new Error(`recovery_binding_missing:${key}`)
104
+ return value
105
+ }
106
+
107
+ function stable(value: unknown): unknown {
108
+ if (Array.isArray(value)) return value.map(stable)
109
+ if (!value || typeof value !== 'object') return value
110
+ return Object.fromEntries(Object.keys(value as Record<string, unknown>).sort().map((key) => [key, stable((value as Record<string, unknown>)[key])]))
111
+ }
112
+
113
+ /** 分类输入 receipt 的规范摘要(键排序后 sha256;证据链锚点)。 */
114
+ export function receiptDigestOf(receipt: ActionReceipt): string {
115
+ return createHash('sha256').update(JSON.stringify(stable(receipt))).digest('hex')
116
+ }
117
+
118
+
119
+ /**
120
+ * 检测(识别分类):把一张 action receipt 分类到恢复链闭集。
121
+ * - offer.availability 观测:完整分类 + 连贯性守卫(与 availability reducer 同一套不变式,
122
+ * 违例抛 availability_receipt_incoherent / availability_observation_required 同名错误);
123
+ * - offers.state 观测:query seam,generation 折叠归 policy 所有 → unrelated;
124
+ * - gap 观测:不可确认 → inconclusive(不得宣称市场无房);
125
+ * - 其余观测上的 changed/unavailable/no_match 是错配凭证 → fail-closed 抛错;
126
+ * 其余状态(applied/partial/…)落在其他 seam → unrelated。
127
+ */
128
+ export function classifyRecoveryTrigger(receipt: ActionReceipt): RecoveryClassification {
129
+ const observation = receipt.observation
130
+ if (observation.kind === 'offers.state') return { kind: 'unrelated', observationKind: observation.kind, reason: 'query seam: generation folding is availability-policy owned' }
131
+ if (observation.kind === 'gap') return { kind: 'inconclusive', reason: `gap observation (${observation.code}): unconfirmable evidence — not_claim_market_empty` }
132
+ if (observation.kind !== 'offer.availability') {
133
+ if (['changed', 'unavailable', 'no_match'].includes(receipt.status)) throw new Error('availability_observation_required')
134
+ return { kind: 'unrelated', observationKind: observation.kind, reason: `receipt status ${receipt.status} rides a non-offer observation` }
135
+ }
136
+ const { offerRef, checkedOfferVersionRef, available, currentOfferVersionRef, verifiedOfferRef, changedFactRefs } = observation
137
+ // 连贯性守卫(镜像 recordOfferCheckReceipt 的 incoherent 判定,fail-closed)
138
+ if (available && (receipt.resultContract.outcome === 'empty' || ['unavailable', 'no_match', 'failed', 'stale', 'unsupported'].includes(receipt.status))) throw new Error('availability_receipt_incoherent')
139
+ if (!available && (verifiedOfferRef || currentOfferVersionRef)) throw new Error('availability_receipt_incoherent')
140
+ if (['unavailable', 'no_match'].includes(receipt.status) && receipt.resultContract.outcome !== 'empty') throw new Error('availability_receipt_incoherent')
141
+ if (receipt.status === 'applied' && available && currentOfferVersionRef === checkedOfferVersionRef && verifiedOfferRef && changedFactRefs.length === 0) {
142
+ return { kind: 'confirmed', offerRef, offerVersionRef: checkedOfferVersionRef, verifiedOfferRef }
143
+ }
144
+ if (receipt.status === 'changed' && available && currentOfferVersionRef && currentOfferVersionRef !== checkedOfferVersionRef) {
145
+ return { kind: 'changed', offerRef, checkedOfferVersionRef, currentOfferVersionRef, changedFactRefs, reason: `supplier superseded ${checkedOfferVersionRef} with ${currentOfferVersionRef} (${changedFactRefs.join(',') || 'unspecified facts'})` }
146
+ }
147
+ if (['unavailable', 'no_match'].includes(receipt.status) && !available) {
148
+ return { kind: 'unavailable', offerRef, offerVersionRef: checkedOfferVersionRef, reason: `complete negative evidence (${receipt.status}, empty outcome)` }
149
+ }
150
+ return { kind: 'inconclusive', reason: `status ${receipt.status}: unconfirmable evidence — partial/stale/failed/gap cannot claim market empty (not_claim_market_empty)` }
151
+ }
152
+
153
+ function isSelection(value: unknown): value is RecoverySelectionRef {
154
+ const candidate = value as RecoverySelectionRef
155
+ return Boolean(candidate && isNonEmpty(candidate.hotelRef) && isNonEmpty(candidate.offerRef) && isNonEmpty(candidate.offerVersionRef))
156
+ }
157
+
158
+ function sameOfferTarget(a: RecoverySelectionRef, b: RecoverySelectionRef): boolean {
159
+ return a.hotelRef === b.hotelRef && a.offerRef === b.offerRef
160
+ }
161
+
162
+ /**
163
+ * 开立恢复链:检测出 changed/unavailable/inconclusive 触发后建链(fail-closed 绑定键 +
164
+ * 首条 recovery.detected 审计事件)。confirmed 无需恢复链、unrelated 无触发,均拒绝开链。
165
+ */
166
+ export function openRecoveryChain(seed: {
167
+ taskId: string
168
+ contextRef: string
169
+ receipt: ActionReceipt
170
+ originalSelection: RecoverySelectionRef
171
+ at: string
172
+ }): RecoveryChainState {
173
+ const taskId = requireBinding('taskId', seed.taskId)
174
+ const contextRef = requireBinding('contextRef', seed.contextRef)
175
+ if (!isNonEmpty(seed.at)) throw new Error('recovery_binding_missing:at')
176
+ const originalSelection = seed.originalSelection
177
+ if (!isSelection(originalSelection)) throw new Error('recovery_binding_missing:originalSelection')
178
+ const classification = classifyRecoveryTrigger(seed.receipt)
179
+ if (classification.kind === 'confirmed') throw new Error('recovery_chain_not_required')
180
+ if (classification.kind === 'unrelated') throw new Error('recovery_trigger_absent')
181
+ return {
182
+ schemaVersion: RECOVERY_CHAIN_SCHEMA,
183
+ taskId,
184
+ contextRef,
185
+ trigger: classification.kind,
186
+ triggerReason: classification.reason,
187
+ originalSelection: { ...originalSelection },
188
+ countedModelTurns: 0,
189
+ phase: 'detected',
190
+ substitutionDisclosed: false,
191
+ history: [{
192
+ at: seed.at,
193
+ kind: 'recovery.detected',
194
+ from: 'detected',
195
+ to: 'detected',
196
+ reason: classification.reason,
197
+ receiptDigest: receiptDigestOf(seed.receipt),
198
+ target: { ...originalSelection },
199
+ }],
200
+ }
201
+ }
202
+
203
+ /**
204
+ * 受控恢复推进:一步一凭证(重查/换版复查/替代候选的检查结果)。
205
+ * - confirmed → resolved;目标与原选择不同酒店/报价且未先披露 = 静默替换,结构性拒绝;
206
+ * - 其余分类 → 计入预算的恢复轮(countedModelTurns + 1,含确认轮);超 3 次拒绝、必须降级;
207
+ * - resolved/degraded 为吸收终态,其后不得再有 attempt。
208
+ */
209
+ export function attemptRecoveryStep(
210
+ state: RecoveryChainState,
211
+ attempt: { receipt: ActionReceipt; target: RecoverySelectionRef; approach: RecoveryApproach },
212
+ at: string,
213
+ ): RecoveryChainState {
214
+ if (state.phase === 'resolved' || state.phase === 'degraded') throw new Error('recovery_chain_terminal')
215
+ if (!RECOVERY_APPROACHES.has(attempt.approach)) throw new Error('recovery_approach_invalid')
216
+ if (!isNonEmpty(at)) throw new Error('recovery_binding_missing:at')
217
+ if (!isSelection(attempt.target)) throw new Error('recovery_binding_missing:target')
218
+ const classification = classifyRecoveryTrigger(attempt.receipt)
219
+ if (classification.kind === 'unrelated') throw new Error('recovery_trigger_absent')
220
+ if (classification.kind === 'confirmed') {
221
+ if (!sameOfferTarget(attempt.target, state.originalSelection) && !state.substitutionDisclosed) {
222
+ throw new Error('recovery_silent_swap_forbidden')
223
+ }
224
+ const versionShifted = attempt.target.offerVersionRef !== state.originalSelection.offerVersionRef
225
+ return {
226
+ ...state,
227
+ phase: 'resolved',
228
+ resolvedTo: { ...attempt.target },
229
+ history: [...state.history, {
230
+ at,
231
+ kind: 'recovery.resolved',
232
+ from: state.phase,
233
+ to: 'resolved',
234
+ reason: `confirmed via ${attempt.approach}${versionShifted ? ' on superseded version' : ''}`,
235
+ receiptDigest: receiptDigestOf(attempt.receipt),
236
+ target: { ...attempt.target },
237
+ substitution: !sameOfferTarget(attempt.target, state.originalSelection),
238
+ }],
239
+ }
240
+ }
241
+ if (state.countedModelTurns + 1 > MAX_RECOVERY_MODEL_TURNS_PER_TRIGGER) {
242
+ throw new Error(`recovery_model_turn_budget_exhausted (${MAX_RECOVERY_MODEL_TURNS_PER_TRIGGER} counted turns per trigger; degrade explicitly instead of retrying)`)
243
+ }
244
+ const reason = classification.reason
245
+ return {
246
+ ...state,
247
+ phase: 'recovering',
248
+ countedModelTurns: state.countedModelTurns + 1,
249
+ history: [...state.history, {
250
+ at,
251
+ kind: 'recovery.attempt',
252
+ from: state.phase,
253
+ to: 'recovering',
254
+ reason: `${attempt.approach}: ${classification.kind}: ${reason}`,
255
+ receiptDigest: receiptDigestOf(attempt.receipt),
256
+ target: { ...attempt.target },
257
+ }],
258
+ }
259
+ }
260
+
261
+ /**
262
+ * 替换披露:恢复将落在与用户原选择不同的酒店/报价上时,必须在确认前显式披露。
263
+ * 空披露文本拒绝——「显式说明变化,不静默换房换航」的结构化落点。
264
+ */
265
+ export function discloseSubstitution(
266
+ state: RecoveryChainState,
267
+ disclosure: { target: RecoverySelectionRef; disclosureText: string; at: string },
268
+ ): RecoveryChainState {
269
+ if (state.phase === 'resolved' || state.phase === 'degraded') throw new Error('recovery_chain_terminal')
270
+ if (!isNonEmpty(disclosure.disclosureText)) throw new Error('recovery_disclosure_required')
271
+ if (!isSelection(disclosure.target)) throw new Error('recovery_binding_missing:target')
272
+ if (!isNonEmpty(disclosure.at)) throw new Error('recovery_binding_missing:at')
273
+ return {
274
+ ...state,
275
+ substitutionDisclosed: true,
276
+ history: [...state.history, {
277
+ at: disclosure.at,
278
+ kind: 'recovery.disclosed',
279
+ from: state.phase,
280
+ to: state.phase,
281
+ reason: disclosure.disclosureText.slice(0, 500),
282
+ target: { ...disclosure.target },
283
+ substitution: true,
284
+ }],
285
+ }
286
+ }
287
+
288
+ /**
289
+ * 显式降级:恢复预算耗尽(或有界候选全负/不可确认)时,只能携非空用户披露降级结束——
290
+ * 静默降级拒绝;降级后链吸收,不得再推进。
291
+ */
292
+ export function degradeRecoveryChain(
293
+ state: RecoveryChainState,
294
+ degrade: { reason: string; disclosureText: string; at: string },
295
+ ): RecoveryChainState {
296
+ if (state.phase === 'resolved' || state.phase === 'degraded') throw new Error('recovery_chain_terminal')
297
+ if (!isNonEmpty(degrade.reason)) throw new Error('recovery_binding_missing:reason')
298
+ if (!isNonEmpty(degrade.disclosureText)) throw new Error('recovery_degrade_requires_disclosure')
299
+ if (!isNonEmpty(degrade.at)) throw new Error('recovery_binding_missing:at')
300
+ return {
301
+ ...state,
302
+ phase: 'degraded',
303
+ history: [...state.history,
304
+ {
305
+ at: degrade.at,
306
+ kind: 'recovery.disclosed',
307
+ from: state.phase,
308
+ to: state.phase,
309
+ reason: degrade.disclosureText.slice(0, 500),
310
+ substitution: false,
311
+ },
312
+ {
313
+ at: degrade.at,
314
+ kind: 'recovery.degraded',
315
+ from: state.phase,
316
+ to: 'degraded',
317
+ reason: degrade.reason.slice(0, 500),
318
+ },
319
+ ],
320
+ }
321
+ }
322
+
323
+ /** 用户沟通投影:结构化披露(substitution/versionShifted/确定性说明文本)。 */
324
+ export function buildUserDisclosure(state: RecoveryChainState): {
325
+ substitution: boolean
326
+ versionShifted: boolean
327
+ text: string
328
+ } {
329
+ if (state.phase === 'resolved' && state.resolvedTo) {
330
+ const substitution = !sameOfferTarget(state.resolvedTo, state.originalSelection)
331
+ const versionShifted = state.resolvedTo.offerVersionRef !== state.originalSelection.offerVersionRef
332
+ if (substitution) {
333
+ return {
334
+ substitution,
335
+ versionShifted,
336
+ text: `Availability changed: original ${state.originalSelection.hotelRef}/${state.originalSelection.offerRef} could not be confirmed (${state.triggerReason}). The substitute ${state.resolvedTo.hotelRef}/${state.resolvedTo.offerRef} is disclosed explicitly for your approval — no silent swap.`,
337
+ }
338
+ }
339
+ if (versionShifted) {
340
+ return {
341
+ substitution,
342
+ versionShifted,
343
+ text: `Availability changed: ${state.originalSelection.offerRef} moved from version ${state.originalSelection.offerVersionRef} to ${state.resolvedTo.offerVersionRef} at the supplier; re-confirmed on the new version.`,
344
+ }
345
+ }
346
+ return { substitution, versionShifted, text: 'Original selection confirmed after recovery.' }
347
+ }
348
+ if (state.phase === 'degraded') {
349
+ return { substitution: false, versionShifted: false, text: `Recovery exhausted for ${state.originalSelection.hotelRef}/${state.originalSelection.offerRef}: ${state.triggerReason}. Task ended explicitly with no substitute booked.` }
350
+ }
351
+ return { substitution: false, versionShifted: false, text: `Recovery in progress: supplier reported ${state.trigger} — ${state.triggerReason}` }
352
+ }
353
+
354
+ /**
355
+ * 审计链校验(形态对齐 booking-saga 的 sagaTraceViolations;空数组 = 链合法):
356
+ * - 必须以恰好一条 recovery.detected 开链;
357
+ * - resolved/degraded 至多各一次且为吸收终态——其后不得有任何事件;
358
+ * - attempt/disclosed 只许出现在终态前;
359
+ * - resolved 目标与 detected 原目标不同酒店/报价时,之前必须有 substitution=true 的披露;
360
+ * - degraded 之前必须有披露事件(静默降级违例)。
361
+ */
362
+ export function recoveryAuditViolations(events: ReadonlyArray<RecoveryAuditEvent>): string[] {
363
+ const violations: string[] = []
364
+ let opened = false
365
+ let detectedTarget: RecoverySelectionRef | undefined
366
+ let terminal: 'resolved' | 'degraded' | undefined
367
+ let disclosedSubstitution = false
368
+ let disclosedSeen = false
369
+ events.forEach((event, index) => {
370
+ const at = `#${index} ${event.kind}`
371
+ if (terminal) { violations.push(`${at}: 终态(${terminal})后出现事件(吸收态)`) ; return }
372
+ switch (event.kind) {
373
+ case 'recovery.detected': {
374
+ if (opened) { violations.push(`${at}: 重复开链`); return }
375
+ opened = true
376
+ detectedTarget = event.target
377
+ return
378
+ }
379
+ case 'recovery.attempt': {
380
+ if (!opened) { violations.push(`${at}: 开链前的 attempt`); return }
381
+ return
382
+ }
383
+ case 'recovery.disclosed': {
384
+ if (!opened) { violations.push(`${at}: 开链前的披露`); return }
385
+ disclosedSeen = true
386
+ if (event.substitution) disclosedSubstitution = true
387
+ return
388
+ }
389
+ case 'recovery.resolved': {
390
+ if (!opened) { violations.push(`${at}: 开链前的 resolved`); return }
391
+ if (detectedTarget && event.target && !sameOfferTarget(event.target, detectedTarget) && !disclosedSubstitution) {
392
+ violations.push(`${at}: 静默替换(resolved 目标偏离原选择且无披露)`)
393
+ }
394
+ terminal = 'resolved'
395
+ return
396
+ }
397
+ case 'recovery.degraded': {
398
+ if (!opened) { violations.push(`${at}: 开链前的 degraded`); return }
399
+ if (!disclosedSeen) violations.push(`${at}: 静默降级(degraded 前无披露)`)
400
+ terminal = 'degraded'
401
+ return
402
+ }
403
+ default:
404
+ violations.push(`${at}: 未知事件 kind`)
405
+ }
406
+ })
407
+ if (!opened) violations.push('链未以 recovery.detected 开立')
408
+ return violations
409
+ }