@danceiny/gotry 0.0.1-rc.9 → 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 (507) hide show
  1. package/README.md +172 -219
  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 -56
  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 +947 -110
  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 +50 -44
  42. package/dist/capabilities/session/adapters/ctrip-flight.js +120 -62
  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 +35 -54
  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 +31 -21
  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 +75 -24
  56. package/dist/capabilities/session/static-flight-golden.js +150 -0
  57. package/dist/capabilities/session/transport.js +97 -83
  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 +635 -44
  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 +24 -59
  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 +50 -11
  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 +25 -70
  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 +382 -246
  191. package/dist/scripts/ledger-workflow-crash.js +10 -20
  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 +18 -52
  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 +24 -12
  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 +39 -28
  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 +20 -20
  227. package/dist/scripts/session-attach-poc.js +34 -37
  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 +14 -35
  231. package/dist/scripts/session-link-tests.js +478 -0
  232. package/dist/scripts/session-login.js +27 -46
  233. package/dist/scripts/session-tests.js +796 -96
  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 +690 -246
  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 +226 -101
  253. package/dist/scripts/state-cli.js +550 -199
  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 +29 -93
  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 +48 -74
  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 +2227 -882
  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 +319 -160
  325. package/dist/src/memory-capture.js +180 -32
  326. package/dist/src/memory-decay.js +30 -14
  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 +435 -516
  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 +44 -63
  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 +535 -359
  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 +293 -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 +1948 -198
  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 +223 -25
  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 +354 -88
  506. package/ts/src/wish-pool.ts +79 -0
  507. package/dist/scripts/session-attach-wait.js +0 -41
@@ -0,0 +1,422 @@
1
+ import assert from 'node:assert/strict';
2
+ import { mkdtempSync, rmSync } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { ensureLedger } from '../src/state-ledger.js';
6
+ import { BookingCopilotTaskRuntime, bookingDigest, bookingTurnDigest, } from '../src/booking-surface/runtime.js';
7
+ import { validateBookingIntentProjection } from '../src/booking-surface/validation.js';
8
+ const contextRef = 'ctx-intent-proof';
9
+ const allowedActions = [
10
+ 'search.patch',
11
+ 'search.run',
12
+ 'results.view.patch',
13
+ 'hotel.focus',
14
+ 'hotel.select',
15
+ 'offers.query',
16
+ 'offers.view.patch',
17
+ 'offers.compare',
18
+ 'offer.select',
19
+ 'offer.check',
20
+ 'checkout.prepare',
21
+ 'order.observe',
22
+ ];
23
+ function workspace(revision = 0) {
24
+ return {
25
+ schemaVersion: 'booking.surface',
26
+ contextRef,
27
+ surface: 'tenant',
28
+ revision,
29
+ locale: 'zh-CN',
30
+ currency: 'AED',
31
+ searchDraft: {},
32
+ results: { status: 'idle' },
33
+ visibleHotels: [],
34
+ loadedOffers: [],
35
+ shortlistedOfferRefs: [],
36
+ capabilities: { surface: 'tenant', allowedActions: [...allowedActions] },
37
+ };
38
+ }
39
+ function turn(taskId, requestText, revision = 0, snapshot = workspace(revision)) {
40
+ return {
41
+ schemaVersion: 'booking.surface',
42
+ kind: 'user.turn',
43
+ taskId,
44
+ turnId: `${taskId}-turn-${revision}`,
45
+ workspace: snapshot,
46
+ request: { text: requestText },
47
+ };
48
+ }
49
+ function action(actionId, revision = 0) {
50
+ return {
51
+ schemaVersion: 'booking.surface',
52
+ kind: 'search.run',
53
+ actionId,
54
+ contextRef,
55
+ expectedRevision: revision,
56
+ reason: 'Run the authoritative workspace search.',
57
+ factRefs: [],
58
+ input: {},
59
+ };
60
+ }
61
+ const compositeIntent = {
62
+ schemaVersion: 'booking.intent.v1',
63
+ target: 'offers.compared',
64
+ offerCriteria: {
65
+ meals: { strength: 'must', value: ['breakfast'] },
66
+ freeCancellation: { strength: 'must', value: true },
67
+ targetCount: 3,
68
+ sort: 'best_match',
69
+ },
70
+ };
71
+ assert.equal(validateBookingIntentProjection(compositeIntent).ok, true, 'canonical composite offer intent is valid');
72
+ for (const invalid of [
73
+ { ...compositeIntent, schemaVersion: 'booking.intent.v2' },
74
+ { ...compositeIntent, target: 'book.now' },
75
+ { ...compositeIntent, payment: { card: '4111 1111 1111 1111' } },
76
+ { ...compositeIntent, offerCriteria: { targetCount: 0 } },
77
+ { ...compositeIntent, offerCriteria: { meals: { strength: 'must', value: [] } } },
78
+ { ...compositeIntent, offerCriteria: { meals: { strength: 'must', value: ['breakfast', 'breakfast'] } } },
79
+ { ...compositeIntent, offerCriteria: { roomType: { strength: 'must', value: ['guest@example.com'] } } },
80
+ { ...compositeIntent, offerCriteria: { roomType: { strength: 'must', value: ['supplier cost AED 10'] } } },
81
+ { schemaVersion: 'booking.intent.v1', target: 'search.results', offerCriteria: { targetCount: 2 } },
82
+ { schemaVersion: 'booking.intent.v1', target: 'results.refined', offerCriteria: { targetCount: 2 } },
83
+ { schemaVersion: 'booking.intent.v1', target: 'hotel.focused', offerCriteria: { targetCount: 2 } },
84
+ { schemaVersion: 'booking.intent.v1', target: 'hotel.selected', offerCriteria: { targetCount: 2 } },
85
+ { schemaVersion: 'booking.intent.v1', target: 'order.observed', offerCriteria: { targetCount: 2 } },
86
+ ]) {
87
+ assert.equal(validateBookingIntentProjection(invalid).ok, false, `invalid intent is rejected: ${JSON.stringify(invalid)}`);
88
+ }
89
+ const root = mkdtempSync(join(tmpdir(), 'gotry-booking-intent-proof-'));
90
+ const taskId = 'task-intent-proof';
91
+ const requestText = '迪拜五星,给我三个含早免费取消的真实报价';
92
+ try {
93
+ const firstLedger = ensureLedger(root);
94
+ const firstRuntime = new BookingCopilotTaskRuntime(firstLedger, { contextRefFactory: () => contextRef });
95
+ const initialTurn = turn(taskId, requestText);
96
+ firstRuntime.startTask(initialTurn);
97
+ assert.throws(() => firstRuntime.issueOperation(taskId, action('intent-missing-direct')), /booking_intent_required/, 'the low-level runtime boundary cannot infer a final user waypoint from a shallow action');
98
+ firstRuntime.applyDecisionBatch(taskId, 'intent-first-operation', [{
99
+ kind: 'operation',
100
+ action: action('intent-search-run'),
101
+ intent: compositeIntent,
102
+ }]);
103
+ const pending = firstRuntime.resumeTask(taskId);
104
+ assert.deepEqual(pending?.activeIntent?.projection, compositeIntent, 'the final user waypoint is bound to the first action');
105
+ assert.equal(pending?.activeIntent?.sourceTurnId, initialTurn.turnId);
106
+ assert.equal(pending?.activeIntent?.sourceRequestDigest, bookingTurnDigest(initialTurn));
107
+ const actionPayloadText = firstLedger.db.prepare("SELECT payload FROM events WHERE run_id = ? AND kind = 'booking.copilot.action.issued'").get(taskId).payload;
108
+ assert.equal(actionPayloadText.includes(requestText), false, 'the action checkpoint stores no raw user request');
109
+ firstLedger.close();
110
+ const receiptWorkspace = {
111
+ ...workspace(1),
112
+ results: { status: 'ready', searchSessionRef: 'search-intent-1', resultCount: 1 },
113
+ visibleHotels: [{ hotelRef: 'hotel-intent-1', name: 'Intent Hotel', factRefs: [] }],
114
+ };
115
+ const receipt = {
116
+ schemaVersion: 'booking.surface',
117
+ kind: 'action.receipt',
118
+ actionId: 'intent-search-run',
119
+ contextRef,
120
+ status: 'applied',
121
+ revision: 1,
122
+ observation: { kind: 'search.state', searchSessionRef: 'search-intent-1', resultCount: 1 },
123
+ resultContract: {
124
+ outcome: 'complete',
125
+ hardCriteriaMet: true,
126
+ factRefs: [],
127
+ gapCodes: [],
128
+ blockers: [],
129
+ relaxationsApplied: [],
130
+ },
131
+ };
132
+ const secondLedger = ensureLedger(root);
133
+ const secondRuntime = new BookingCopilotTaskRuntime(secondLedger, { contextRefFactory: () => contextRef });
134
+ const replayedPending = secondRuntime.resumeTask(taskId);
135
+ assert.deepEqual(replayedPending?.activeIntent?.projection, compositeIntent, 'process restart replays the exact semantic goal');
136
+ const afterReceipt = secondRuntime.continueWithReceipt({
137
+ schemaVersion: 'booking.surface',
138
+ kind: 'action.receipt.continuation',
139
+ taskId,
140
+ workspace: receiptWorkspace,
141
+ receipt,
142
+ });
143
+ assert.deepEqual(afterReceipt.activeIntent?.projection, compositeIntent, 'an intermediate receipt cannot shorten the user goal');
144
+ assert.equal(afterReceipt.lastCompletedAction?.kind, 'search.run');
145
+ assert.throws(() => secondRuntime.applyDecisionBatch(taskId, 'intent-missing-operation', [{
146
+ kind: 'operation',
147
+ action: {
148
+ schemaVersion: 'booking.surface',
149
+ kind: 'offers.query',
150
+ actionId: 'intent-missing-query',
151
+ contextRef,
152
+ expectedRevision: 1,
153
+ reason: 'Attempt to omit the durable goal.',
154
+ factRefs: [],
155
+ input: { hotelRefs: ['hotel-intent-1'], criteria: compositeIntent.offerCriteria },
156
+ },
157
+ }]), /invalid_booking_intent/, 'a model-facing operation cannot rely on runtime inference when intent is missing');
158
+ assert.throws(() => secondRuntime.applyDecisionBatch(taskId, 'intent-weakened-operation', [{
159
+ kind: 'operation',
160
+ action: {
161
+ schemaVersion: 'booking.surface',
162
+ kind: 'offers.query',
163
+ actionId: 'intent-weakened-query',
164
+ contextRef,
165
+ expectedRevision: 1,
166
+ reason: 'Attempt to execute weaker criteria than the durable goal.',
167
+ factRefs: [],
168
+ input: { hotelRefs: ['hotel-intent-1'], criteria: { targetCount: 1 } },
169
+ },
170
+ intent: compositeIntent,
171
+ }]), /action_intent_mismatch/, 'a later action cannot execute weaker criteria than the durable semantic goal');
172
+ secondRuntime.applyDecisionBatch(taskId, 'intent-next-operation', [{
173
+ kind: 'operation',
174
+ action: {
175
+ schemaVersion: 'booking.surface',
176
+ kind: 'offers.query',
177
+ actionId: 'intent-offers-query',
178
+ contextRef,
179
+ expectedRevision: 1,
180
+ reason: 'Load authoritative offers for the visible candidate.',
181
+ factRefs: [],
182
+ input: { hotelRefs: ['hotel-intent-1'], criteria: compositeIntent.offerCriteria },
183
+ },
184
+ intent: compositeIntent,
185
+ }]);
186
+ assert.deepEqual(secondRuntime.resumeTask(taskId)?.activeIntent?.projection, compositeIntent, 'a later action reuses the durable goal without model prose');
187
+ assert.throws(() => secondRuntime.applyDecisionBatch(taskId, 'intent-mutated-operation', [{
188
+ kind: 'operation',
189
+ action: {
190
+ schemaVersion: 'booking.surface',
191
+ kind: 'offers.query',
192
+ actionId: 'intent-mutated-query',
193
+ contextRef,
194
+ expectedRevision: 1,
195
+ reason: 'Attempt to mutate the goal.',
196
+ factRefs: [],
197
+ input: { hotelRefs: ['hotel-intent-1'], criteria: { targetCount: 1 } },
198
+ },
199
+ intent: { ...compositeIntent, offerCriteria: { targetCount: 1 } },
200
+ }]), /receipt_required|intent_mutation_forbidden/, 'the model cannot replace an in-flight semantic goal');
201
+ secondLedger.close();
202
+ }
203
+ finally {
204
+ rmSync(root, { recursive: true, force: true });
205
+ }
206
+ function tamperIntent(name, mutate) {
207
+ const tamperRoot = mkdtempSync(join(tmpdir(), `gotry-booking-intent-${name}-`));
208
+ const tamperTaskId = `task-intent-${name}`;
209
+ try {
210
+ const ledger = ensureLedger(tamperRoot);
211
+ const runtime = new BookingCopilotTaskRuntime(ledger, { contextRefFactory: () => contextRef });
212
+ runtime.startTask(turn(tamperTaskId, 'find hotels'));
213
+ runtime.applyDecisionBatch(tamperTaskId, `${name}-operation`, [{
214
+ kind: 'operation',
215
+ action: action(`${name}-action`),
216
+ intent: compositeIntent,
217
+ }]);
218
+ const row = ledger.db.prepare("SELECT seq, payload FROM events WHERE run_id = ? AND kind = 'booking.copilot.action.issued'").get(tamperTaskId);
219
+ const payload = JSON.parse(row.payload);
220
+ payload.intent = mutate(payload.intent);
221
+ ledger.db.prepare('UPDATE events SET payload = ? WHERE seq = ?').run(JSON.stringify(payload), row.seq);
222
+ assert.throws(() => runtime.resumeTask(tamperTaskId), new RegExp(`ledger_corrupt:${tamperTaskId}:intent`), `${name} intent tampering is fail-closed`);
223
+ ledger.close();
224
+ }
225
+ finally {
226
+ rmSync(tamperRoot, { recursive: true, force: true });
227
+ }
228
+ }
229
+ tamperIntent('projection', (checkpoint) => ({
230
+ ...checkpoint,
231
+ projection: { ...checkpoint.projection, target: 'search.results' },
232
+ }));
233
+ tamperIntent('digest', (checkpoint) => ({ ...checkpoint, intentDigest: '0'.repeat(64) }));
234
+ tamperIntent('source-turn', (checkpoint) => {
235
+ const base = { ...checkpoint, sourceTurnId: 'forged-turn' };
236
+ const { intentDigest: _old, ...digestInput } = base;
237
+ return { ...base, intentDigest: bookingDigest(digestInput) };
238
+ });
239
+ tamperIntent('source-request', (checkpoint) => {
240
+ const base = { ...checkpoint, sourceRequestDigest: 'f'.repeat(64) };
241
+ const { intentDigest: _old, ...digestInput } = base;
242
+ return { ...base, intentDigest: bookingDigest(digestInput) };
243
+ });
244
+ tamperIntent('task-graft', (checkpoint) => {
245
+ const base = { ...checkpoint, taskId: 'task-from-another-ledger' };
246
+ const { intentDigest: _old, ...digestInput } = base;
247
+ return { ...base, intentDigest: bookingDigest(digestInput) };
248
+ });
249
+ tamperIntent('context-graft', (checkpoint) => {
250
+ const base = { ...checkpoint, contextRef: 'ctx-from-another-actor' };
251
+ const { intentDigest: _old, ...digestInput } = base;
252
+ return { ...base, intentDigest: bookingDigest(digestInput) };
253
+ });
254
+ // Expand compatibility: old ACTION rows without a typed intent remain
255
+ // additive-readable, but their action/receipt tail is safely replanned rather
256
+ // than left pending or allowed to terminalize a task.
257
+ {
258
+ const legacyRoot = mkdtempSync(join(tmpdir(), 'gotry-booking-intent-legacy-'));
259
+ const legacyTaskId = 'task-intent-legacy';
260
+ try {
261
+ const ledger = ensureLedger(legacyRoot);
262
+ const runtime = new BookingCopilotTaskRuntime(ledger, { contextRefFactory: () => contextRef });
263
+ runtime.startTask(turn(legacyTaskId, 'find hotels'));
264
+ runtime.issueOperation(legacyTaskId, action('legacy-intent-action'), { schemaVersion: 'booking.intent.v1', target: 'search.results' });
265
+ const receiptWorkspace = {
266
+ ...workspace(1),
267
+ results: { status: 'ready', searchSessionRef: 'legacy-search-1', resultCount: 1 },
268
+ };
269
+ runtime.continueWithReceipt({
270
+ schemaVersion: 'booking.surface',
271
+ kind: 'action.receipt.continuation',
272
+ taskId: legacyTaskId,
273
+ workspace: receiptWorkspace,
274
+ receipt: {
275
+ schemaVersion: 'booking.surface',
276
+ kind: 'action.receipt',
277
+ actionId: 'legacy-intent-action',
278
+ contextRef,
279
+ status: 'applied',
280
+ revision: 1,
281
+ observation: { kind: 'search.state', searchSessionRef: 'legacy-search-1', resultCount: 1 },
282
+ resultContract: { outcome: 'complete', hardCriteriaMet: true, factRefs: [], gapCodes: [], blockers: [], relaxationsApplied: [] },
283
+ },
284
+ });
285
+ const row = ledger.db.prepare("SELECT seq, payload FROM events WHERE run_id = ? AND kind = 'booking.copilot.action.issued'").get(legacyTaskId);
286
+ const payload = JSON.parse(row.payload);
287
+ delete payload.intent;
288
+ ledger.db.prepare('UPDATE events SET payload = ? WHERE seq = ?').run(JSON.stringify(payload), row.seq);
289
+ ledger.close();
290
+ const replayLedger = ensureLedger(legacyRoot);
291
+ const replayRuntime = new BookingCopilotTaskRuntime(replayLedger, { contextRefFactory: () => contextRef });
292
+ const replayed = replayRuntime.resumeTask(legacyTaskId);
293
+ assert.equal(replayed?.pendingAction, undefined, 'legacy action/receipt replay must not remain pending');
294
+ assert.equal(replayed?.activeIntent, undefined, 'legacy action replay does not invent a later user goal');
295
+ assert.equal(replayed?.lastReceipt, undefined, 'legacy receipt replay does not become current evidence');
296
+ assert.equal(replayed?.replayUpgradeRequired, true, 'legacy action/receipt replay requires a fresh turn anchor');
297
+ assert.equal(replayed?.phase, 'planning', 'legacy action/receipt replay remains replannable, not terminal');
298
+ assert.throws(() => replayRuntime.issueOperation(legacyTaskId, action('legacy-missing-intent')), /booking_intent_required/, 'untyped legacy two-argument call still fails closed at runtime');
299
+ replayLedger.close();
300
+ }
301
+ finally {
302
+ rmSync(legacyRoot, { recursive: true, force: true });
303
+ }
304
+ }
305
+ // A legal action kind paired with an overshooting intent is rejected at issue
306
+ // time and from a tampered replay row using the same ordinal table.
307
+ {
308
+ const pathRoot = mkdtempSync(join(tmpdir(), 'gotry-booking-intent-path-'));
309
+ try {
310
+ const ledger = ensureLedger(pathRoot);
311
+ const runtime = new BookingCopilotTaskRuntime(ledger, { contextRefFactory: () => contextRef });
312
+ const pathTaskId = 'task-intent-path';
313
+ runtime.startTask(turn(pathTaskId, 'search'));
314
+ assert.throws(() => runtime.applyDecisionBatch(pathTaskId, 'invalid-search-offer-criteria', [{
315
+ kind: 'operation', action: action('invalid-search-offer-criteria'),
316
+ intent: { schemaVersion: 'booking.intent.v1', target: 'search.results', offerCriteria: { targetCount: 2 } },
317
+ }]), /invalid_booking_intent/, 'same-turn intent schema rejects offer criteria on a search waypoint');
318
+ assert.throws(() => runtime.applyDecisionBatch(pathTaskId, 'overshoot-at-issue', [{
319
+ kind: 'operation',
320
+ action: { ...action('overshoot-check'), kind: 'offer.check', input: { offerRef: 'offer-path', offerVersionRef: 'offer-path:v1' } },
321
+ intent: { schemaVersion: 'booking.intent.v1', target: 'search.results' },
322
+ }]), /action_intent_mismatch/, 'a legal action cannot overshoot its durable intent target');
323
+ runtime.applyDecisionBatch(pathTaskId, 'path-valid-prefix', [{
324
+ kind: 'operation',
325
+ action: action('path-search-run'),
326
+ intent: { schemaVersion: 'booking.intent.v1', target: 'offers.compared', offerCriteria: { targetCount: 3 } },
327
+ }]);
328
+ const row = ledger.db.prepare("SELECT seq, payload FROM events WHERE run_id = ? AND kind = 'booking.copilot.action.issued'").get(pathTaskId);
329
+ const payload = JSON.parse(row.payload);
330
+ payload.intent = { ...payload.intent, projection: { ...payload.intent.projection, target: 'search.results' } };
331
+ ledger.db.prepare('UPDATE events SET payload = ? WHERE seq = ?').run(JSON.stringify(payload), row.seq);
332
+ assert.throws(() => runtime.resumeTask(pathTaskId), new RegExp(`ledger_corrupt:${pathTaskId}:intent`), 'the same target/action path rule is enforced during replay');
333
+ ledger.close();
334
+ }
335
+ finally {
336
+ rmSync(pathRoot, { recursive: true, force: true });
337
+ }
338
+ }
339
+ // Existing-order observation is an independent waypoint. Preparing Checkout
340
+ // belongs to the current booking journey; after user authorization/Book a new
341
+ // trusted order context starts observation.
342
+ {
343
+ const checkoutRoot = mkdtempSync(join(tmpdir(), 'gotry-booking-intent-checkout-'));
344
+ try {
345
+ const ledger = ensureLedger(checkoutRoot);
346
+ const runtime = new BookingCopilotTaskRuntime(ledger, { contextRefFactory: () => contextRef });
347
+ const checkoutTaskId = 'task-intent-order-observed';
348
+ runtime.startTask(turn(checkoutTaskId, 'observe an existing order'));
349
+ assert.throws(() => runtime.applyDecisionBatch(checkoutTaskId, 'order-observed-checkout', [{
350
+ kind: 'operation',
351
+ action: {
352
+ schemaVersion: 'booking.surface', kind: 'checkout.prepare', actionId: 'order-observed-checkout-action', contextRef,
353
+ expectedRevision: 0, reason: 'Prepare checkout before observing order.', factRefs: [],
354
+ input: { offerRef: 'offer-order-1', offerVersionRef: 'offer-order-1:v1', verifiedOfferRef: 'verified-order-1' },
355
+ },
356
+ intent: { schemaVersion: 'booking.intent.v1', target: 'order.observed' },
357
+ }]), /action_intent_mismatch/, 'checkout.prepare cannot advance an independent order.observed intent');
358
+ ledger.close();
359
+ }
360
+ finally {
361
+ rmSync(checkoutRoot, { recursive: true, force: true });
362
+ }
363
+ }
364
+ // A projection can name only a waypoint supported by the current surface.
365
+ {
366
+ const narrowRoot = mkdtempSync(join(tmpdir(), 'gotry-booking-intent-narrow-'));
367
+ try {
368
+ const ledger = ensureLedger(narrowRoot);
369
+ const runtime = new BookingCopilotTaskRuntime(ledger, { contextRefFactory: () => contextRef });
370
+ const narrowWorkspace = {
371
+ ...workspace(),
372
+ capabilities: { surface: 'tenant', allowedActions: ['search.run'] },
373
+ };
374
+ runtime.startTask(turn('task-intent-narrow', 'find and compare offers', 0, narrowWorkspace));
375
+ assert.throws(() => runtime.applyDecisionBatch('task-intent-narrow', 'narrow-operation', [{
376
+ kind: 'operation',
377
+ action: action('narrow-action'),
378
+ intent: compositeIntent,
379
+ }]), /intent_target_unsupported/, 'intent cannot expand the surface capability allowlist');
380
+ ledger.close();
381
+ }
382
+ finally {
383
+ rmSync(narrowRoot, { recursive: true, force: true });
384
+ }
385
+ }
386
+ // Count semantics are part of the durable goal, not advisory model prose.
387
+ {
388
+ const countRoot = mkdtempSync(join(tmpdir(), 'gotry-booking-intent-count-'));
389
+ try {
390
+ const ledger = ensureLedger(countRoot);
391
+ const runtime = new BookingCopilotTaskRuntime(ledger, { contextRefFactory: () => contextRef });
392
+ const countWorkspace = {
393
+ ...workspace(),
394
+ loadedOffers: [{ offerRef: 'offer-count-1', offerVersionRef: 'offer-count-1:v1', hotelRef: 'hotel-count-1', evidenceLevel: 'rate_loaded', factRefs: [] }],
395
+ capabilities: { surface: 'tenant', allowedActions: ['offers.compare'] },
396
+ };
397
+ runtime.startTask(turn('task-intent-count', 'compare three offers', 0, countWorkspace));
398
+ assert.throws(() => runtime.applyDecisionBatch('task-intent-count', 'count-mismatch-operation', [{
399
+ kind: 'operation',
400
+ action: {
401
+ schemaVersion: 'booking.surface',
402
+ kind: 'offers.compare',
403
+ actionId: 'count-mismatch-action',
404
+ contextRef,
405
+ expectedRevision: 0,
406
+ reason: 'Attempt to compare fewer offers than requested.',
407
+ factRefs: [],
408
+ input: { offerRefs: ['offer-count-1'], requestedCount: 1 },
409
+ },
410
+ intent: {
411
+ schemaVersion: 'booking.intent.v1',
412
+ target: 'offers.compared',
413
+ offerCriteria: { targetCount: 3 },
414
+ },
415
+ }]), /action_intent_mismatch/, 'requestedCount cannot be weakened below the durable comparison target');
416
+ ledger.close();
417
+ }
418
+ finally {
419
+ rmSync(countRoot, { recursive: true, force: true });
420
+ }
421
+ }
422
+ console.log('BOOKING COPILOT INTENT PROOF: canonical validation/persistence/restart/tamper/legacy/capability OK');
@@ -0,0 +1,184 @@
1
+ import assert from 'node:assert/strict';
2
+ import { existsSync, mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
3
+ import { spawn } from 'node:child_process';
4
+ import { tmpdir } from 'node:os';
5
+ import { join } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { ensureLedger } from '../src/state-ledger.js';
8
+ import { BookingCopilotTaskRuntime as StrictBookingCopilotTaskRuntime } from '../src/booking-surface/runtime.js';
9
+ const taskId = 'task-operation-atomicity';
10
+ const workspace = {
11
+ schemaVersion: 'booking.surface', contextRef: 'ctx-operation-atomicity', surface: 'tenant', revision: 0,
12
+ locale: 'en-US', currency: 'AED', searchDraft: {}, results: { status: 'idle' }, visibleHotels: [], loadedOffers: [], shortlistedOfferRefs: [],
13
+ capabilities: { surface: 'tenant', allowedActions: ['search.patch', 'search.run'] },
14
+ };
15
+ const base = { schemaVersion: 'booking.surface', kind: 'search.patch', actionId: 'action-operation-atomicity', contextRef: workspace.contextRef, expectedRevision: 0, reason: 'raw-reason-marker', factRefs: ['fact:opaque'], input: { patch: { destination: { query: 'typed-input-marker' } } } };
16
+ const searchResultsIntent = { schemaVersion: 'booking.intent.v1', target: 'search.results' };
17
+ const child = process.argv.indexOf('--child') >= 0;
18
+ const replayMode = process.argv.indexOf('--replay') >= 0;
19
+ const root = child ? process.argv[process.argv.indexOf('--child') + 1] : '';
20
+ const variant = child ? process.argv[process.argv.indexOf('--child') + 2] : '';
21
+ if (replayMode) {
22
+ const replayRoot = process.argv[process.argv.indexOf('--replay') + 1];
23
+ const replayVariant = process.argv[process.argv.indexOf('--replay') + 2] ?? 'base';
24
+ const replayLedger = ensureLedger(replayRoot);
25
+ const replayAction = replayVariant === 'conflict' ? action('conflict') : replayVariant === 'different' ? action('different') : base;
26
+ try {
27
+ console.log(JSON.stringify({ result: 'success', event: new StrictBookingCopilotTaskRuntime(replayLedger).issueOperation(taskId, replayAction, searchResultsIntent) }));
28
+ }
29
+ catch (error) {
30
+ console.log(JSON.stringify({ result: 'error', error: error instanceof Error ? error.message : String(error) }));
31
+ }
32
+ replayLedger.close();
33
+ process.exit(0);
34
+ }
35
+ function waitFile(path, timeout = 30_000) { return new Promise((resolve, reject) => { const end = Date.now() + timeout; const tick = () => existsSync(path) ? resolve() : Date.now() > end ? reject(new Error(`timeout:${path}`)) : setTimeout(tick, 5); tick(); }); }
36
+ function action(which) {
37
+ return {
38
+ ...base,
39
+ kind: which === 'kind' ? 'search.run' : base.kind,
40
+ reason: which === 'conflict' ? 'different reason' : base.reason,
41
+ contextRef: which === 'context' ? 'ctx-other' : base.contextRef,
42
+ expectedRevision: which === 'revision' ? 1 : base.expectedRevision,
43
+ factRefs: which === 'fact-order' ? ['fact:other', 'fact:opaque'] : base.factRefs,
44
+ input: which === 'kind' ? {} : which === 'input' ? { patch: { destination: { query: 'other' } } } : base.input,
45
+ actionId: which === 'different' ? 'action-different' : base.actionId,
46
+ };
47
+ }
48
+ if (child) {
49
+ const ledger = ensureLedger(root);
50
+ const runtime = new StrictBookingCopilotTaskRuntime(ledger);
51
+ const original = runtime.resumeTask.bind(runtime);
52
+ let first = true;
53
+ writeFileSync(join(root, `started-${variant}`), 'started');
54
+ const gateEnd = Date.now() + 10_000;
55
+ while (!existsSync(join(root, 'start'))) {
56
+ if (Date.now() > gateEnd)
57
+ throw new Error('start_gate_timeout');
58
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 5);
59
+ }
60
+ if (variant !== 'left')
61
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 100);
62
+ runtime.resumeTask = (id) => { const state = original(id); if (first && !state?.pendingAction) {
63
+ first = false;
64
+ writeFileSync(join(root, `ready-${variant}`), 'ready');
65
+ const end = Date.now() + 10_000;
66
+ while (!existsSync(join(root, 'release'))) {
67
+ if (Date.now() > end)
68
+ throw new Error('barrier_timeout');
69
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 5);
70
+ }
71
+ } return state; };
72
+ try {
73
+ const event = runtime.issueOperation(taskId, action(variant), searchResultsIntent);
74
+ console.log(JSON.stringify({ result: 'success', event }));
75
+ }
76
+ catch (error) {
77
+ console.log(JSON.stringify({ result: 'error', error: error instanceof Error ? error.message : String(error) }));
78
+ }
79
+ ledger.close();
80
+ process.exit(0);
81
+ }
82
+ async function pair(root, left, right) {
83
+ const tsx = fileURLToPath(new URL('../node_modules/tsx/dist/cli.mjs', import.meta.url));
84
+ const script = fileURLToPath(import.meta.url);
85
+ const ps = [left, right].map((v) => spawn(process.execPath, [tsx, script, '--child', root, v], { cwd: process.cwd(), stdio: ['ignore', 'pipe', 'pipe'] }));
86
+ const out = ps.map(() => '');
87
+ ps.forEach((p, i) => { p.stdout.on('data', (b) => { out[i] += b; }); p.stderr.on('data', (b) => { out[i] += b; }); });
88
+ await Promise.all([waitFile(join(root, `started-${left}`)), waitFile(join(root, `started-${right}`))]);
89
+ writeFileSync(join(root, 'start'), 'start');
90
+ try {
91
+ await Promise.race([waitFile(join(root, `ready-${left}`)), waitFile(join(root, `ready-${right}`))]);
92
+ }
93
+ catch (error) {
94
+ ps.forEach((p) => p.kill('SIGKILL'));
95
+ throw new Error(`workers_did_not_reach_callsite:${out.join('|')}:${error}`);
96
+ }
97
+ await new Promise((resolve) => setTimeout(resolve, 250));
98
+ assert.equal(existsSync(join(root, `ready-${left}`)) && existsSync(join(root, `ready-${right}`)), false, 'both workers entered transaction before release');
99
+ writeFileSync(join(root, 'release'), 'release');
100
+ try {
101
+ await Promise.all(ps.map((p) => new Promise((resolve, reject) => { const timer = setTimeout(() => reject(new Error('worker_timeout')), 10_000); p.on('exit', (code) => { clearTimeout(timer); code === 0 ? resolve() : reject(new Error(`worker_exit:${code}:${out.join('|')}`)); }); })));
102
+ }
103
+ finally {
104
+ ps.forEach((p) => { if (p.exitCode === null)
105
+ p.kill('SIGKILL'); });
106
+ }
107
+ return out.map((s) => JSON.parse(s.trim().split('\n').at(-1)));
108
+ }
109
+ async function run(kind, conflictVariant = 'conflict') {
110
+ const root = mkdtempSync(join(tmpdir(), `gotry-operation-${kind}-`));
111
+ mkdirSync(root, { recursive: true });
112
+ const ledger = ensureLedger(root);
113
+ const runtime = new StrictBookingCopilotTaskRuntime(ledger);
114
+ const turn = { schemaVersion: 'booking.surface', kind: 'user.turn', taskId, turnId: 'operation-anchor-turn', workspace, request: { text: 'opaque' } };
115
+ runtime.startTask(turn);
116
+ const result = await pair(root, kind === 'different' ? 'different' : 'left', kind === 'conflict' ? conflictVariant : 'right');
117
+ const success = result.filter((r) => r.result === 'success');
118
+ assert.equal(success.length, kind === 'same' ? 2 : 1);
119
+ if (kind === 'conflict')
120
+ assert.equal(result.filter((r) => r.error === 'action_conflict').length, 1, JSON.stringify(result));
121
+ if (kind === 'different')
122
+ assert.equal(result.filter((r) => r.error === 'receipt_required').length, 1);
123
+ if (kind === 'same')
124
+ assert.deepEqual(success[0].event, success[1].event);
125
+ assert.equal(ledger.db.prepare("SELECT COUNT(*) AS n FROM events WHERE kind = 'booking.copilot.action.issued'").get().n, 1);
126
+ const durable = ledger.db.prepare("SELECT payload FROM events WHERE kind = 'booking.copilot.action.issued'").get();
127
+ assert.ok(!/raw-reason-marker|@example|secret/i.test(durable.payload), 'action reason prose is never durable');
128
+ assert.match(durable.payload, /"reasonDigest"/, 'the redacted reason digest is durable');
129
+ if (kind === 'same') {
130
+ const event = success[0].event;
131
+ ledger.close();
132
+ const tsx = fileURLToPath(new URL('../node_modules/tsx/dist/cli.mjs', import.meta.url));
133
+ async function replayVariant(v) { const replayChild = spawn(process.execPath, [tsx, fileURLToPath(import.meta.url), '--replay', root, v], { cwd: process.cwd(), stdio: ['ignore', 'pipe', 'pipe'] }); let replayOutput = ''; replayChild.stdout.on('data', (b) => { replayOutput += b; }); replayChild.stderr.on('data', (b) => { replayOutput += b; }); await new Promise((resolve, reject) => { const timer = setTimeout(() => { replayChild.kill('SIGKILL'); reject(new Error('replay_timeout')); }, 10_000); replayChild.on('exit', (code) => { clearTimeout(timer); code === 0 ? resolve() : reject(new Error(`replay_exit:${code}:${replayOutput}`)); }); }); return JSON.parse(replayOutput.trim().split('\n').at(-1)); }
134
+ const replayResult = await replayVariant('base');
135
+ assert.deepEqual(replayResult.event, event);
136
+ const conflictResult = await replayVariant('conflict');
137
+ assert.equal(conflictResult.error, 'action_conflict');
138
+ const differentResult = await replayVariant('different');
139
+ assert.equal(differentResult.error, 'receipt_required');
140
+ const restarted = ensureLedger(root);
141
+ assert.equal(restarted.db.prepare("SELECT COUNT(*) AS n FROM events WHERE kind = 'booking.copilot.action.issued'").get().n, 1);
142
+ const replay = replayResult.event;
143
+ const pending = new StrictBookingCopilotTaskRuntime(restarted).resumeTask(taskId)?.pendingAction;
144
+ assert.deepEqual(pending && { eventId: pending.eventId, sequence: pending.sequence, emittedAt: pending.emittedAt }, { eventId: replay.eventId, sequence: replay.sequence, emittedAt: replay.emittedAt });
145
+ restarted.close();
146
+ }
147
+ else {
148
+ ledger.close();
149
+ }
150
+ rmSync(root, { recursive: true, force: true });
151
+ }
152
+ if (!child) {
153
+ for (let round = 0; round < 20; round++) {
154
+ await run('same');
155
+ await run('conflict', ['conflict', 'kind', 'context', 'revision', 'fact-order', 'input'][round % 6]);
156
+ await run('different');
157
+ }
158
+ const unsafeRoot = mkdtempSync(join(tmpdir(), 'gotry-operation-unsafe-'));
159
+ const unsafeLedger = ensureLedger(unsafeRoot);
160
+ const unsafeRuntime = new StrictBookingCopilotTaskRuntime(unsafeLedger);
161
+ unsafeRuntime.startTask({ schemaVersion: 'booking.surface', kind: 'user.turn', taskId, turnId: 'unsafe-anchor-turn', workspace, request: { text: 'opaque' } });
162
+ assert.throws(() => unsafeRuntime.issueOperation(taskId, { ...base, reason: 'raw prose marker@example.invalid' }, searchResultsIntent), /invalid_action|unsafe/, 'email prose is rejected before an operation is issued');
163
+ assert.throws(() => unsafeRuntime.issueOperation(taskId, { ...base, factRefs: ['attacker@example.invalid'] }, searchResultsIntent), /invalid_action|unsafe_fact_ref/);
164
+ assert.throws(() => unsafeRuntime.issueOperation(taskId, { ...base, actionId: 'attacker@example.invalid' }, searchResultsIntent), /invalid_action|unsafe_action_id/);
165
+ assert.throws(() => unsafeRuntime.issueOperation(taskId, { ...base, actionId: 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.signature' }, searchResultsIntent), /invalid_action|unsafe_action_id/);
166
+ assert.equal(unsafeLedger.countEvents(), 2);
167
+ unsafeLedger.close();
168
+ rmSync(unsafeRoot, { recursive: true, force: true });
169
+ for (const field of ['actionId', 'factRefs', 'expectedRevision']) {
170
+ const tamperRoot = mkdtempSync(join(tmpdir(), `gotry-operation-tamper-${field}-`));
171
+ const tamperLedger = ensureLedger(tamperRoot);
172
+ const tamperRuntime = new StrictBookingCopilotTaskRuntime(tamperLedger);
173
+ tamperRuntime.startTask({ schemaVersion: 'booking.surface', kind: 'user.turn', taskId, turnId: 'tamper-anchor-turn', workspace, request: { text: 'opaque' } });
174
+ tamperRuntime.issueOperation(taskId, base, searchResultsIntent);
175
+ const row = tamperLedger.db.prepare("SELECT seq, payload FROM events WHERE kind = 'booking.copilot.action.issued'").get();
176
+ const payload = JSON.parse(row.payload);
177
+ payload.action[field] = field === 'factRefs' ? ['tampered'] : field === 'expectedRevision' ? 99 : 'tampered-action';
178
+ tamperLedger.db.prepare('UPDATE events SET payload = ? WHERE seq = ?').run(JSON.stringify(payload), row.seq);
179
+ assert.throws(() => new StrictBookingCopilotTaskRuntime(tamperLedger).resumeTask(taskId), /ledger_corrupt/);
180
+ tamperLedger.close();
181
+ rmSync(tamperRoot, { recursive: true, force: true });
182
+ }
183
+ console.log('BOOKING COPILOT OPERATION LEDGER CONCURRENCY PROOF: 20 rounds atomic');
184
+ }