@danceiny/gotry 0.0.1-rc.21 → 0.0.1-rc.24

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 (327) hide show
  1. package/README.md +102 -194
  2. package/README.zh-CN.md +115 -210
  3. package/bin/gotry-backend.js +53 -0
  4. package/bin/gotry-bootstrap.js +466 -35
  5. package/bin/gotry-inner.js +255 -36
  6. package/bin/gotry-process-liveness.d.ts +27 -0
  7. package/bin/gotry-process-liveness.js +97 -0
  8. package/bin/gotry-runtime-resolution.d.ts +1 -1
  9. package/bin/gotry-runtime-resolution.js +2 -2
  10. package/client/client.js +174 -0
  11. package/cordis.gotry-patch.yml +70 -93
  12. package/dist/capabilities/agent-reach-deep.js +45 -122
  13. package/dist/capabilities/agent-reach.js +63 -148
  14. package/dist/capabilities/anything.js +89 -75
  15. package/dist/capabilities/artifacts.js +123 -104
  16. package/dist/capabilities/channel-health.js +65 -45
  17. package/dist/capabilities/channel-registry.js +108 -87
  18. package/dist/capabilities/doctor.js +357 -235
  19. package/dist/capabilities/effect.js +223 -309
  20. package/dist/capabilities/fact-log.js +28 -14
  21. package/dist/capabilities/flyai.js +245 -156
  22. package/dist/capabilities/ground-transfer.js +509 -0
  23. package/dist/capabilities/hbcli.js +144 -148
  24. package/dist/capabilities/hotelbyte-transaction.js +194 -0
  25. package/dist/capabilities/incident-log.js +131 -61
  26. package/dist/capabilities/model-override.js +30 -10
  27. package/dist/capabilities/opensky.js +54 -43
  28. package/dist/capabilities/resilience.js +50 -32
  29. package/dist/capabilities/session/action-cache.js +50 -44
  30. package/dist/capabilities/session/adapters/ctrip-flight.js +119 -62
  31. package/dist/capabilities/session/adapters/ctrip-hotel.js +125 -110
  32. package/dist/capabilities/session/adapters/dida-portal.js +206 -0
  33. package/dist/capabilities/session/adapters/meituan-local.js +35 -54
  34. package/dist/capabilities/session/adapters/rail-12306.js +169 -112
  35. package/dist/capabilities/session/benchmark.js +85 -149
  36. package/dist/capabilities/session/extension-bridge.js +320 -259
  37. package/dist/capabilities/session/extension-channel.js +57 -76
  38. package/dist/capabilities/session/extension-distribution.js +115 -119
  39. package/dist/capabilities/session/extract.js +31 -21
  40. package/dist/capabilities/session/golden-score.js +55 -33
  41. package/dist/capabilities/session/health-watch.js +146 -154
  42. package/dist/capabilities/session/read-guard.js +55 -47
  43. package/dist/capabilities/session/static-flight-golden.js +49 -36
  44. package/dist/capabilities/session/transport.js +54 -61
  45. package/dist/capabilities/session/wizard.js +63 -93
  46. package/dist/capabilities/session-consent.js +143 -47
  47. package/dist/capabilities/session-login.js +95 -126
  48. package/dist/capabilities/session-search.js +391 -253
  49. package/dist/capabilities/sponsor-plugin.js +341 -0
  50. package/dist/capabilities/visa-policy.js +87 -73
  51. package/dist/capabilities/weather.js +163 -235
  52. package/dist/scripts/action-cache-tests.js +24 -59
  53. package/dist/scripts/agent-planning-turn-deadline-e2e.js +91 -142
  54. package/dist/scripts/agent-planning-turn-deadline-tests.js +80 -176
  55. package/dist/scripts/agent-reach-deep-tests.js +30 -40
  56. package/dist/scripts/agent-reach-tests.js +26 -18
  57. package/dist/scripts/agent-reach-wrapper-tests.js +46 -50
  58. package/dist/scripts/anything-tests.js +58 -62
  59. package/dist/scripts/artifact-client-contract-tests.js +69 -0
  60. package/dist/scripts/artifacts-capability-tests.js +235 -0
  61. package/dist/scripts/async-collect.js +26 -15
  62. package/dist/scripts/benchmark-environment-bridge-e2e.js +287 -684
  63. package/dist/scripts/benchmark-environment-bridge-tests.js +818 -3123
  64. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +66 -279
  65. package/dist/scripts/booking-copilot-availability-policy-tests.js +153 -1257
  66. package/dist/scripts/booking-copilot-bin-proof-tests.js +22 -45
  67. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +64 -76
  68. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +69 -199
  69. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +393 -759
  70. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +33 -75
  71. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +60 -110
  72. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +28 -66
  73. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +72 -271
  74. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +73 -275
  75. package/dist/scripts/booking-copilot-runtime-proof-tests.js +784 -3398
  76. package/dist/scripts/booking-copilot-server-proof-tests.js +63 -168
  77. package/dist/scripts/booking-copilot-startup-proof-tests.js +38 -124
  78. package/dist/scripts/booking-executor-tests.js +80 -0
  79. package/dist/scripts/booking-recovery-chain-tests.js +182 -0
  80. package/dist/scripts/booking-saga-tests.js +61 -123
  81. package/dist/scripts/booking-surface-contract-proof-tests.js +152 -1167
  82. package/dist/scripts/bootstrap-tests.js +1383 -128
  83. package/dist/scripts/build-changelog.js +89 -130
  84. package/dist/scripts/build-metrics-report.js +135 -143
  85. package/dist/scripts/changelog-tests.js +35 -82
  86. package/dist/scripts/channel-probe-tests.js +44 -116
  87. package/dist/scripts/channel-probe.js +84 -167
  88. package/dist/scripts/channel-registry-tests.js +97 -185
  89. package/dist/scripts/companion-tests.js +25 -70
  90. package/dist/scripts/dida-cookie-probe.js +87 -0
  91. package/dist/scripts/dida-sw-probe.js +114 -0
  92. package/dist/scripts/diff-test.js +17 -12
  93. package/dist/scripts/doctor-tests.js +428 -120
  94. package/dist/scripts/dsh-artifact-e2e.js +150 -0
  95. package/dist/scripts/dsh-artifact-web-e2e.js +443 -0
  96. package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
  97. package/dist/scripts/dsh-runtime-closure-tests.js +110 -153
  98. package/dist/scripts/dsh-runtime-closure.js +75 -63
  99. package/dist/scripts/dsh-session-v3-migration-proof.js +106 -0
  100. package/dist/scripts/dsh-subprocess-local-proof.js +149 -0
  101. package/dist/scripts/dsh-target-closure-proof.js +178 -0
  102. package/dist/scripts/effect-tests.js +165 -552
  103. package/dist/scripts/engine-run.js +1 -3
  104. package/dist/scripts/engine-tests.js +16 -10
  105. package/dist/scripts/evaluation-cadence-tests.js +69 -242
  106. package/dist/scripts/evaluation-contract-tests.js +193 -499
  107. package/dist/scripts/extension-distribution-cli.js +19 -15
  108. package/dist/scripts/extension-distribution-tests.js +98 -211
  109. package/dist/scripts/extension-tests.js +366 -389
  110. package/dist/scripts/fact-gate-tests.js +725 -263
  111. package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
  112. package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
  113. package/dist/scripts/flight-malformed-tests.js +159 -0
  114. package/dist/scripts/flyai-tests.js +325 -68
  115. package/dist/scripts/g5-guard-tests.js +131 -0
  116. package/dist/scripts/g5-guard.js +189 -0
  117. package/dist/scripts/gen-lunar-anchors.js +106 -0
  118. package/dist/scripts/gotry-backend-kernel-tests.js +79 -0
  119. package/dist/scripts/ground-transfer-tests.js +956 -0
  120. package/dist/scripts/hbcli-e2e-tests.js +71 -90
  121. package/dist/scripts/hbcli-live-optin-tests.js +96 -0
  122. package/dist/scripts/hbcli-release-contract-tests.js +122 -0
  123. package/dist/scripts/hbcli-tests.js +41 -115
  124. package/dist/scripts/health-watch-cli.js +42 -28
  125. package/dist/scripts/hotel-date-gate-tests.js +496 -0
  126. package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
  127. package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
  128. package/dist/scripts/i18n-tests.js +16 -9
  129. package/dist/scripts/incident-tests.js +281 -87
  130. package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
  131. package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
  132. package/dist/scripts/issue-271-liveness-tests.js +547 -0
  133. package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
  134. package/dist/scripts/issue-289-model-retry-tests.js +441 -0
  135. package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
  136. package/dist/scripts/issue-338-home-city-e2e.js +577 -0
  137. package/dist/scripts/issue343-real-entry-e2e.js +160 -0
  138. package/dist/scripts/journey-tests.js +22 -27
  139. package/dist/scripts/kernel-manifest-evidence.js +109 -0
  140. package/dist/scripts/kernel-manifest-gate.js +126 -0
  141. package/dist/scripts/kernel-manifest-tests.js +212 -0
  142. package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
  143. package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
  144. package/dist/scripts/kernel-manifest.js +369 -0
  145. package/dist/scripts/ledger-repair-apply-tests.js +316 -0
  146. package/dist/scripts/ledger-repair-plan-tests.js +375 -0
  147. package/dist/scripts/ledger-tests.js +325 -340
  148. package/dist/scripts/ledger-workflow-crash.js +10 -20
  149. package/dist/scripts/map-tools-vendor-package-proof.js +206 -134
  150. package/dist/scripts/memory-capture-tests.js +242 -61
  151. package/dist/scripts/memory-decay-tests.js +18 -52
  152. package/dist/scripts/memory-lifecycle-tests.js +657 -0
  153. package/dist/scripts/memory-lifecycle.js +196 -0
  154. package/dist/scripts/memory-metrics.js +24 -12
  155. package/dist/scripts/memory-value-report.js +474 -222
  156. package/dist/scripts/memory-value-tests.js +328 -0
  157. package/dist/scripts/metrics-report-tests.js +62 -199
  158. package/dist/scripts/model-override-e2e.js +66 -105
  159. package/dist/scripts/nightly-evidence-tests.js +64 -89
  160. package/dist/scripts/nightly-evidence.js +108 -111
  161. package/dist/scripts/nudge-digest.js +39 -28
  162. package/dist/scripts/onboarding-tests.js +63 -88
  163. package/dist/scripts/opensky-check.js +18 -13
  164. package/dist/scripts/opensky-tests.js +28 -28
  165. package/dist/scripts/persona-surface-guard-tests.js +37 -12
  166. package/dist/scripts/pnpm-dsh-closure-proof.js +2 -5
  167. package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
  168. package/dist/scripts/price-drift-tests.js +126 -227
  169. package/dist/scripts/price-drift-watch.js +209 -253
  170. package/dist/scripts/probe-poi-tests.js +52 -45
  171. package/dist/scripts/product-metrics.js +187 -273
  172. package/dist/scripts/publish-preverify.js +47 -41
  173. package/dist/scripts/realtime-pricing-tests.js +37 -76
  174. package/dist/scripts/replay-async.js +20 -18
  175. package/dist/scripts/replay-real.js +16 -18
  176. package/dist/scripts/replay.js +52 -82
  177. package/dist/scripts/session-attach-diagnose.js +16 -12
  178. package/dist/scripts/session-attach-poc.js +34 -37
  179. package/dist/scripts/session-benchmark.js +66 -147
  180. package/dist/scripts/session-dida-live-e2e.js +151 -0
  181. package/dist/scripts/session-extract-tests.js +14 -35
  182. package/dist/scripts/session-login.js +14 -13
  183. package/dist/scripts/session-tests.js +545 -583
  184. package/dist/scripts/sf-live-benchmark.js +92 -110
  185. package/dist/scripts/sf-live-cli-tests.js +2 -9
  186. package/dist/scripts/sf-soft-score-tests.js +19 -60
  187. package/dist/scripts/sf-summary-tests.js +149 -0
  188. package/dist/scripts/sf-summary.js +466 -84
  189. package/dist/scripts/skeleton-check.js +16 -14
  190. package/dist/scripts/skeleton-integration-test.js +11 -10
  191. package/dist/scripts/skills-contract-tests.js +51 -46
  192. package/dist/scripts/smoke-session-gate-tests.js +12 -20
  193. package/dist/scripts/smoke.js +541 -422
  194. package/dist/scripts/sponsor-reuse-tests.js +262 -0
  195. package/dist/scripts/state-cli-tests.js +226 -101
  196. package/dist/scripts/state-cli.js +549 -212
  197. package/dist/scripts/static-golden-tests.js +46 -180
  198. package/dist/scripts/time-eval-tests.js +210 -192
  199. package/dist/scripts/travel-timeline-tests.js +29 -93
  200. package/dist/scripts/turn-handoff-collect-tests.js +46 -93
  201. package/dist/scripts/turn-handoff-collect.js +71 -99
  202. package/dist/scripts/turn-policy-tests.js +28 -29
  203. package/dist/scripts/typed-contract-canary.js +77 -162
  204. package/dist/scripts/tz-resolver-sanity.js +50 -0
  205. package/dist/scripts/tz-resolver-tests.js +584 -0
  206. package/dist/scripts/unified-tests.js +23 -19
  207. package/dist/scripts/visa-policy-tests.js +31 -44
  208. package/dist/scripts/weather-tests.js +121 -543
  209. package/dist/scripts/wish-channel-gate-tests.js +29 -86
  210. package/dist/scripts/write-gate-tests.js +522 -0
  211. package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
  212. package/dist/scripts/z3-lifecycle-tests.js +170 -0
  213. package/dist/scripts/z3-race-repeat-tests.js +39 -0
  214. package/dist/scripts/z3-race-tests.js +18 -12
  215. package/dist/src/artifact-gate.js +652 -221
  216. package/dist/src/backend/kernel.js +91 -0
  217. package/dist/src/backend/modules/booking-copilot.js +55 -0
  218. package/dist/src/backend/modules/booking-executor.js +124 -0
  219. package/dist/src/backend/modules/session-search.js +194 -0
  220. package/dist/src/benchmark-agent-conformance.js +296 -262
  221. package/dist/src/benchmark-environment-bridge.js +298 -413
  222. package/dist/src/benchmark-headless-child-diagnostics.js +93 -100
  223. package/dist/src/benchmark-tool-isolation.js +94 -67
  224. package/dist/src/bookable-facts.js +299 -174
  225. package/dist/src/booking-saga.js +64 -120
  226. package/dist/src/booking-surface/availability-policy.js +443 -576
  227. package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
  228. package/dist/src/booking-surface/contracts.js +24 -80
  229. package/dist/src/booking-surface/dsh-planner.js +510 -281
  230. package/dist/src/booking-surface/dsh-plugin.js +17 -1
  231. package/dist/src/booking-surface/error-codes.js +82 -10
  232. package/dist/src/booking-surface/index.js +0 -3
  233. package/dist/src/booking-surface/profile.js +10 -54
  234. package/dist/src/booking-surface/recovery-chain.js +367 -0
  235. package/dist/src/booking-surface/runtime.js +765 -891
  236. package/dist/src/booking-surface/server.js +200 -251
  237. package/dist/src/booking-surface/startup.js +58 -54
  238. package/dist/src/booking-surface/validation.js +150 -218
  239. package/dist/src/bridge.js +20 -13
  240. package/dist/src/companions.js +48 -74
  241. package/dist/src/contracts.js +21 -43
  242. package/dist/src/dsh-llm.js +82 -120
  243. package/dist/src/engine.js +253 -239
  244. package/dist/src/evaluation-cadence.js +72 -209
  245. package/dist/src/evaluation-contracts.js +220 -843
  246. package/dist/src/flight-pack-adapter.js +54 -0
  247. package/dist/src/flight-pack-contract.js +2 -0
  248. package/dist/src/gotry-backend.js +70 -0
  249. package/dist/src/hotel-date-gate.js +118 -0
  250. package/dist/src/i18n.js +18 -7
  251. package/dist/src/index.js +1425 -1629
  252. package/dist/src/journey.js +132 -81
  253. package/dist/src/ledger-repair-apply.js +538 -0
  254. package/dist/src/ledger-repair-plan.js +463 -0
  255. package/dist/src/loop.js +257 -166
  256. package/dist/src/memory-capture.js +180 -32
  257. package/dist/src/memory-decay.js +30 -14
  258. package/dist/src/memory-lifecycle.js +1310 -0
  259. package/dist/src/memory-utility.js +27 -40
  260. package/dist/src/mock-llm.js +36 -61
  261. package/dist/src/model.js +81 -36
  262. package/dist/src/realtime-pricing.js +63 -72
  263. package/dist/src/slot-spec.js +84 -106
  264. package/dist/src/state-ledger.js +310 -471
  265. package/dist/src/subagent-job-id-guard.js +58 -0
  266. package/dist/src/time-anchor.js +231 -33
  267. package/dist/src/tool-packet.js +20 -8
  268. package/dist/src/travel-slots.js +58 -35
  269. package/dist/src/travel-timeline.js +44 -63
  270. package/dist/src/turn-deadline.js +121 -127
  271. package/dist/src/turn-policy.js +61 -89
  272. package/dist/src/tz-resolver.js +143 -0
  273. package/dist/src/unified.js +504 -381
  274. package/dist/src/wish-pool.js +39 -14
  275. package/dist/src/write-gate.js +495 -0
  276. package/dist/src/z3-shared.js +273 -7
  277. package/extension/README.md +4 -3
  278. package/extension/background.js +125 -14
  279. package/extension/content-bridge.js +23 -1
  280. package/extension/content-main.js +15 -4
  281. package/extension/manifest.json +16 -8
  282. package/package.json +251 -220
  283. package/ts/capabilities/agent-reach.ts +4 -4
  284. package/ts/capabilities/anything.ts +1 -1
  285. package/ts/capabilities/artifacts.ts +46 -9
  286. package/ts/capabilities/flyai.ts +156 -37
  287. package/ts/capabilities/hbcli.ts +1 -1
  288. package/ts/capabilities/incident-log.ts +88 -59
  289. package/ts/capabilities/session/adapters/ctrip-flight.ts +99 -36
  290. package/ts/capabilities/session/adapters/dida-portal.ts +250 -0
  291. package/ts/capabilities/session/adapters/rail-12306.ts +123 -24
  292. package/ts/capabilities/session/extension-bridge.ts +226 -101
  293. package/ts/capabilities/session/extension-channel.ts +22 -9
  294. package/ts/capabilities/session/wizard.ts +2 -2
  295. package/ts/capabilities/session-consent.ts +98 -14
  296. package/ts/capabilities/session-login.ts +1 -0
  297. package/ts/capabilities/session-search.ts +315 -31
  298. package/ts/dsh-runtime/vendor/README.md +8 -4
  299. package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +7 -1
  300. package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +5 -3
  301. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +1 -1
  302. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +1 -1
  303. package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +6 -6
  304. package/ts/package.json +236 -16
  305. package/ts/scripts/map-tools-vendor-package-proof.ts +152 -31
  306. package/ts/scripts/state-cli.ts +418 -51
  307. package/ts/src/artifact-gate.ts +561 -15
  308. package/ts/src/benchmark-environment-bridge.ts +37 -20
  309. package/ts/src/bookable-facts.ts +183 -7
  310. package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
  311. package/ts/src/booking-surface/dsh-planner.ts +240 -32
  312. package/ts/src/booking-surface/dsh-plugin.js +17 -1
  313. package/ts/src/booking-surface/error-codes.ts +75 -0
  314. package/ts/src/booking-surface/recovery-chain.ts +409 -0
  315. package/ts/src/booking-surface/server.ts +84 -51
  316. package/ts/src/booking-surface/validation.ts +2 -0
  317. package/ts/src/contracts.ts +12 -2
  318. package/ts/src/dsh-llm.ts +4 -8
  319. package/ts/src/index.ts +609 -90
  320. package/ts/src/loop.ts +116 -7
  321. package/ts/src/memory-capture.ts +227 -3
  322. package/ts/src/mock-llm.ts +4 -8
  323. package/ts/src/model.ts +88 -2
  324. package/ts/src/state-ledger.ts +47 -29
  325. package/ts/src/subagent-job-id-guard.ts +72 -0
  326. package/ts/src/time-anchor.ts +217 -13
  327. package/ts/src/unified.ts +316 -54
@@ -260,8 +260,6 @@ interface CollectedText {
260
260
  }
261
261
 
262
262
  interface SubprocessHandle {
263
- /** DSH reports -1 when process creation itself failed. */
264
- readonly pid: number
265
263
  collected: { stdout: CollectedText; stderr: CollectedText }
266
264
  done: Promise<{ exitCode: number | null; signal?: string | null }>
267
265
  terminate?: () => void
@@ -461,22 +459,44 @@ export function registerBenchmarkEnvironmentBridge(
461
459
  }
462
460
  env.PYTHONDONTWRITEBYTECODE = '1'
463
461
  env.PYTHONNOUSERSITE = '1'
464
- handle = subprocess.spawn({
465
- argv: [bridge.executable, ...bridge.argv_prefix, 'call', tool, serialized.json!],
466
- cwd: bridge.cwd,
467
- stdio: {
468
- stdin: 'ignore',
469
- stdout: { maxBytes: bridge.max_output_bytes },
470
- stderr: { maxBytes: bridge.max_output_bytes },
471
- },
472
- graceMs: Math.min(1_000, bridge.timeout_ms),
473
- env,
474
- signal: controller.signal,
475
- })
476
- const status = await handle.done
462
+ try {
463
+ handle = subprocess.spawn({
464
+ argv: [bridge.executable, ...bridge.argv_prefix, 'call', tool, serialized.json!],
465
+ cwd: bridge.cwd,
466
+ stdio: {
467
+ stdin: 'ignore',
468
+ stdout: { maxBytes: bridge.max_output_bytes },
469
+ stderr: { maxBytes: bridge.max_output_bytes },
470
+ },
471
+ graceMs: Math.min(1_000, bridge.timeout_ms),
472
+ env,
473
+ signal: controller.signal,
474
+ })
475
+ } catch {
476
+ if (controller.signal.aborted) return jsonObject({ ok: false, error: 'timed_out' })
477
+ return jsonObject({ ok: false, error: 'spawn_failed' })
478
+ }
479
+ let status: { exitCode: number | null; signal?: string | null }
480
+ try {
481
+ status = await handle!.done
482
+ } catch {
483
+ if (controller.signal.aborted) return jsonObject({ ok: false, error: 'timed_out' })
484
+ return jsonObject({ ok: false, error: 'spawn_failed' })
485
+ }
477
486
  if (controller.signal.aborted) return jsonObject({ ok: false, error: 'timed_out' })
478
- const stdout = handle.collected.stdout.readFrom(0)
479
- const stderr = handle.collected.stderr.readFrom(0)
487
+ let stdout: { text: string; lossy?: boolean }
488
+ let stderr: { text: string; lossy?: boolean }
489
+ try {
490
+ stdout = handle!.collected.stdout.readFrom(0)
491
+ stderr = handle!.collected.stderr.readFrom(0)
492
+ } catch {
493
+ return jsonObject({
494
+ ok: false,
495
+ error: 'runner_failed',
496
+ exit_code: status.exitCode,
497
+ signal: status.signal ?? null,
498
+ })
499
+ }
480
500
  if (stdout.lossy || stderr.lossy) return jsonObject({ ok: false, error: 'output_truncated' })
481
501
  if (status.exitCode !== 0) {
482
502
  return jsonObject({
@@ -504,9 +524,6 @@ export function registerBenchmarkEnvironmentBridge(
504
524
  if (!plainObject(visibleResult) && !Array.isArray(visibleResult)) return jsonObject({ ok: false, error: 'invalid_output' })
505
525
  if (!inspectAllowedOutput(visibleResult, descriptor.output_keys)) return jsonObject({ ok: false, error: 'forbidden_output' })
506
526
  return jsonObject({ ok: true, result: visibleResult })
507
- } catch {
508
- if (controller.signal.aborted) return jsonObject({ ok: false, error: 'timed_out' })
509
- return jsonObject({ ok: false, error: !handle || handle.pid === -1 ? 'spawn_failed' : 'runner_failed' })
510
527
  } finally {
511
528
  clearTimeout(timer)
512
529
  }
@@ -20,6 +20,7 @@
20
20
  */
21
21
 
22
22
  import { createHash } from 'node:crypto'
23
+ import { hasRecognizedAvailableSeat, validateTrainQueryResponseUrl, type SessionTrainOption } from '../capabilities/session/adapters/rail-12306.ts'
23
24
 
24
25
  export const BOOKABLE_FACT_SCHEMA = 'gotry_bookable_fact.v1' as const
25
26
 
@@ -182,6 +183,25 @@ export interface SessionLikeResult {
182
183
  options?: SessionLikeOption[]
183
184
  }
184
185
 
186
+ /** 12306 exact-date fact freshness rule: capture must be non-future and <=15 minutes old. */
187
+ export const TRAIN_FACT_FRESHNESS_RULE = 'captured_at_non_future_and_max_age_15m' as const
188
+ export const TRAIN_FACT_MAX_AGE_MS = 15 * 60 * 1000
189
+
190
+ export interface SessionTrainFactResult {
191
+ outcome: {
192
+ kind: 'recognized-nonempty' | 'recognized-empty' | 'malformed' | 'transport-runtime-error'
193
+ trains?: SessionTrainOption[]
194
+ }
195
+ collection?: {
196
+ requested: { from: string; to: string; date: string }
197
+ request: { fromStationTelecode: string; toStationTelecode: string; date: string }
198
+ response: { url: string; fromStationTelecode: string; toStationTelecode: string; date: string }
199
+ batchId: string
200
+ queryId: string
201
+ fetchedAt: string
202
+ }
203
+ }
204
+
185
205
  const YMD = /^\d{4}-\d{2}-\d{2}$/
186
206
 
187
207
  function hmOf(dateTime: string | undefined): string | undefined {
@@ -289,6 +309,67 @@ export function factsFromSession(q: { origin: string; destination: string; date:
289
309
  return facts
290
310
  }
291
311
 
312
+ function trainCollectionIsFresh(
313
+ q: { from: string; to: string; date: string },
314
+ r: SessionTrainFactResult,
315
+ now: Date,
316
+ ): r is SessionTrainFactResult & { collection: NonNullable<SessionTrainFactResult['collection']> } {
317
+ const c = r.collection
318
+ if (!c || !c.batchId.trim() || !c.queryId.trim() || c.queryId !== `session:12306-train:${c.batchId}`) return false
319
+ if (c.requested.from !== q.from || c.requested.to !== q.to || c.requested.date !== q.date) return false
320
+ if (!c.request || !c.response
321
+ || c.request.date !== c.requested.date
322
+ || c.response.fromStationTelecode !== c.request.fromStationTelecode
323
+ || c.response.toStationTelecode !== c.request.toStationTelecode
324
+ || c.response.date !== c.request.date
325
+ || !validateTrainQueryResponseUrl(c.response.url, c.request).ok) return false
326
+ const fetchedMs = Date.parse(c.fetchedAt)
327
+ const nowMs = now.getTime()
328
+ if (!Number.isFinite(fetchedMs) || !Number.isFinite(nowMs)) return false
329
+ return fetchedMs <= nowMs && nowMs - fetchedMs <= TRAIN_FACT_MAX_AGE_MS
330
+ }
331
+
332
+ /** 12306 typed outcome → exact-date train facts.
333
+ * The converter never invents collection identity or timestamps: both must come
334
+ * from the session invocation binding. Only recognized-empty can create a
335
+ * negative fact. A recognized row needs Y plus a closed-set available seat token.
336
+ */
337
+ export function factsFromSessionTrain(
338
+ q: { from: string; to: string; date: string },
339
+ r: SessionTrainFactResult,
340
+ now: Date = new Date(),
341
+ ): FlightFact[] {
342
+ if (!trainCollectionIsFresh(q, r, now)) return []
343
+ const c = r.collection
344
+ const source = 'session:12306-train'
345
+ const fetchedAt = c.fetchedAt
346
+ if (r.outcome.kind === 'recognized-empty') {
347
+ return [negativeFact(c.queryId, 'train', q.from, q.to, q.date, source, fetchedAt)]
348
+ }
349
+ if (r.outcome.kind !== 'recognized-nonempty') return []
350
+ const facts: FlightFact[] = []
351
+ for (const o of r.outcome.trains ?? []) {
352
+ if (o.canWebBuy !== 'Y' || !hasRecognizedAvailableSeat(o)) continue
353
+ facts.push({
354
+ schema: BOOKABLE_FACT_SCHEMA,
355
+ fact_id: makeFactId(['train', q.from, q.to, q.date, o.trainCode, c.queryId]),
356
+ kind: 'train',
357
+ route: { origin: q.from, destination: q.to },
358
+ date: q.date,
359
+ flight_no: o.trainCode,
360
+ dep_local: o.depTime,
361
+ arr_local: o.arrTime,
362
+ tier: 'live_inventory',
363
+ bookability: 'bookable_exact_date',
364
+ source,
365
+ query_id: c.queryId,
366
+ fetched_at: fetchedAt,
367
+ as_of: fetchedAt.slice(0, 10),
368
+ })
369
+ }
370
+ return facts
371
+ }
372
+
292
373
  // ---------------------------------------------------------------------------
293
374
  // 注册表(纯函数视图;持久化在 capabilities/fact-log.ts)
294
375
  // ---------------------------------------------------------------------------
@@ -304,9 +385,13 @@ export function dedupeFacts<T extends BookableFact>(facts: T[]): T[] {
304
385
  }
305
386
 
306
387
  /** route+date 的最新查询结论(同日多次查询:最新一次为准,避免「昨天 miss 今天 hit」陈旧否定) */
307
- export function latestFactsForRouteDate(facts: BookableFact[], origin: string, destination: string, date: string): FlightFact[] {
388
+ export function latestFactsForRouteDate(
389
+ facts: BookableFact[], origin: string, destination: string, date: string,
390
+ kind?: 'flight' | 'train',
391
+ ): FlightFact[] {
308
392
  const hits = facts.filter((f): f is FlightFact =>
309
393
  (f.kind === 'flight' || f.kind === 'train')
394
+ && (!kind || f.kind === kind)
310
395
  && f.route.origin === origin && f.route.destination === destination && f.date === date)
311
396
  const latestQueryTs = new Map<string, string>()
312
397
  for (const f of hits) {
@@ -319,7 +404,7 @@ export function latestFactsForRouteDate(facts: BookableFact[], origin: string, d
319
404
  }
320
405
 
321
406
  // ---------------------------------------------------------------------------
322
- // 判定原语①:航班 claim 可述性(fail closed)
407
+ // 判定原语①:航班 claim 可述性(fail closed,flight-only)
323
408
  // ---------------------------------------------------------------------------
324
409
 
325
410
  export type FlightClaimVerdict =
@@ -335,10 +420,16 @@ export interface FlightClaim {
335
420
  date?: string
336
421
  }
337
422
 
423
+ /**
424
+ * 航班 claim 裁决(flight-only):注册表只接受 `kind:'flight'` 的同号事实
425
+ * ——train 事实走 `railClaimVerdict` 独立裁决,不得混入航班 not_in_source
426
+ * 路径(issue #299)。中文高铁/动车/城际/直达代码(G/D/C/Z + 3–4 位)在
427
+ * 闸侧 `extractClaims` 已分流到 `trains` claim,本函数无需再做扩展。
428
+ */
338
429
  export function flightClaimVerdict(facts: BookableFact[], claim: FlightClaim): { verdict: FlightClaimVerdict; fact?: FlightFact; reason: string } {
339
430
  const no = claim.flight_no.toUpperCase().replace(/\s+/g, '')
340
431
  const sameNo = facts.filter((f): f is FlightFact =>
341
- (f.kind === 'flight' || f.kind === 'train') && f.flight_no.toUpperCase() === no && f.bookability === 'bookable_exact_date')
432
+ f.kind === 'flight' && f.flight_no.toUpperCase() === no && f.bookability === 'bookable_exact_date')
342
433
  const routeMatched = sameNo.filter(f =>
343
434
  (!claim.origin || f.route.origin === claim.origin || f.route.origin_airport === claim.origin)
344
435
  && (!claim.destination || f.route.destination === claim.destination || f.route.dest_airport === claim.destination)
@@ -346,7 +437,7 @@ export function flightClaimVerdict(facts: BookableFact[], claim: FlightClaim): {
346
437
  if (routeMatched.length > 0) return { verdict: 'traceable', fact: routeMatched[0], reason: `回溯 ${routeMatched[0]!.query_id}` }
347
438
  // 无同号可下单事实:该 route+date 是否查过?
348
439
  if (claim.origin && claim.destination && claim.date) {
349
- const scoped = latestFactsForRouteDate(facts, claim.origin, claim.destination, claim.date)
440
+ const scoped = latestFactsForRouteDate(facts, claim.origin, claim.destination, claim.date, 'flight')
350
441
  if (scoped.length > 0) {
351
442
  return {
352
443
  verdict: 'not_in_source',
@@ -360,6 +451,63 @@ export function flightClaimVerdict(facts: BookableFact[], claim: FlightClaim): {
360
451
  return { verdict: 'route_unqueried', reason: `航班 ${no} 无可回溯的 exact-date 事实(缺 route/date 上下文)` }
361
452
  }
362
453
 
454
+ // ---------------------------------------------------------------------------
455
+ // 判定原语①b:车次 claim 可述性(rail-only,fail closed;issue #299)
456
+ // 闸侧 `extractClaims` 已把 G/D/C/Z + 3–4 位 token 收集为 train claim;
457
+ // 本裁决只在 train 事实里查同号 bookable_exact_date,缺事实/缺上下文/
458
+ // 路线未查均 fail-closed。支持的事实生产端是 `factsFromFlyai kind:'train'`
459
+ // 与 `factsFromSessionTrain`,两者均经真实工具路径追加到事实日志; session
460
+ // 结果必须先通过 typed parser outcome + seat availability/freshness contract。
461
+ // 不得用历史班期或 static-schedule 凑合格回溯。
462
+ // ---------------------------------------------------------------------------
463
+
464
+ export type RailClaimVerdict =
465
+ | 'traceable' // 注册表内有 bookable_exact_date 的该 train 事实(同号+同 route+同 date)
466
+ | 'not_in_source' // 该 route+date 查过 exact-date,结果里没有它——最强违例
467
+ | 'route_unqueried' // 该 route+date 从未查过 exact-date——无证据断言
468
+ | 'rail_claim_unverified' // 缺 route/date 上下文,或缺同号事实且 route/date 无 exact-date 证据
469
+
470
+ export interface RailClaim {
471
+ flight_no: string
472
+ origin?: string
473
+ destination?: string
474
+ date?: string
475
+ }
476
+
477
+ const TRAIN_FACT_SOURCES = new Set(['flyai', 'session:12306-train'])
478
+
479
+ function isStructuredTrainFact(f: BookableFact): f is FlightFact {
480
+ return f.kind === 'train'
481
+ && f.schema === BOOKABLE_FACT_SCHEMA
482
+ && TRAIN_FACT_SOURCES.has(f.source)
483
+ && f.query_id.trim().length > 0
484
+ && f.tier === 'live_inventory'
485
+ }
486
+
487
+ export function railClaimVerdict(facts: BookableFact[], claim: RailClaim): { verdict: RailClaimVerdict; fact?: FlightFact; reason: string } {
488
+ const no = claim.flight_no.toUpperCase().replace(/\s+/g, '')
489
+ if (!claim.origin || !claim.destination || !claim.date) {
490
+ return { verdict: 'rail_claim_unverified', reason: `车次 ${no} 无可回溯的 exact-date 事实(缺完整 route/date 上下文)` }
491
+ }
492
+ // 先按 train kind 选择该 route+date 的最新查询批次,再在该批次匹配车次。
493
+ // 这样旧 hit 不会越过更新的 miss/unavailable,flight 批次也不能遮蔽 train 批次。
494
+ const scoped = latestFactsForRouteDate(facts, claim.origin, claim.destination, claim.date, 'train')
495
+ .filter(isStructuredTrainFact)
496
+ const sameNo = scoped.filter(f =>
497
+ f.flight_no.toUpperCase() === no
498
+ && f.bookability === 'bookable_exact_date')
499
+ if (sameNo.length > 0) return { verdict: 'traceable', fact: sameNo[0], reason: `回溯 ${sameNo[0]!.query_id}` }
500
+ if (scoped.length > 0) {
501
+ return {
502
+ verdict: 'not_in_source',
503
+ reason: scoped.some(f => f.bookability === 'unavailable_exact_date')
504
+ ? `${claim.origin}→${claim.destination} ${claim.date} train exact-date 源返回 0 条(${scoped[0]!.query_id})——不得用历史班期/相邻日期填充`
505
+ : `${claim.origin}→${claim.destination} ${claim.date} train exact-date 源在架 ${scoped.filter(f => f.bookability === 'bookable_exact_date').map(f => f.flight_no).join('/')}——无 ${no}`,
506
+ }
507
+ }
508
+ return { verdict: 'route_unqueried', reason: `${claim.origin}→${claim.destination} ${claim.date} train 路线从未经 exact-date 源核验` }
509
+ }
510
+
363
511
  // ---------------------------------------------------------------------------
364
512
  // 判定原语②:同日衔接硬约束(办事结束 → 门到机场 → 值机截止 → 起飞)
365
513
  // ---------------------------------------------------------------------------
@@ -405,7 +553,7 @@ export function checkSameDayDeparture(
405
553
  c: SameDayDepartureConstraint,
406
554
  ): SameDayDepartureVerdict {
407
555
  const earliest = hmToMin(c.errand_end_local) + c.airport_transit_min + c.checkin_deadline_min
408
- const scoped = latestFactsForRouteDate(facts, q.origin, q.destination, q.date)
556
+ const scoped = latestFactsForRouteDate(facts, q.origin, q.destination, q.date, 'flight')
409
557
  const nonstopBookable = scoped.filter(f => f.bookability === 'bookable_exact_date' && f.nonstop !== false)
410
558
  const feasible: FlightFact[] = []
411
559
  const excluded: Array<{ flight_no: string; reason: string }> = []
@@ -526,8 +674,9 @@ export function defaultReviewBy(tripDate: string): string {
526
674
  }
527
675
 
528
676
  /**
529
- * 航班事实行。bookable_exact_date 才允许完整班次行;其余一律 fail-closed 措辞。
530
- * 永不输出无条件 ✓;证据链(source/query_id/fetched_at)随行必达。
677
+ * 航班/车次事实行。bookable_exact_date 才允许完整班次行;其余一律 fail-closed 措辞。
678
+ * train 复用此 canonical renderer 但只输出车次语义,不输出直飞或价格;永不输出无条件 ✓;
679
+ * 证据链(source/query_id/fetched_at)随行必达。
531
680
  */
532
681
  export function renderFlightFact(f: FlightFact): string {
533
682
  return renderFlightFactInner(f) + ` <!-- fact:${f.fact_id} -->`
@@ -538,6 +687,13 @@ function renderFlightFactInner(f: FlightFact): string {
538
687
  const anchor = ` <!-- fact:${f.fact_id} -->`
539
688
  const route = `${f.route.origin}→${f.route.destination}`
540
689
  const evidence = `[${f.source}@${f.fetched_at} #${f.query_id}]`
690
+ if (f.kind === 'train' && f.bookability === 'unavailable_exact_date') {
691
+ const review = f.review_by ?? defaultReviewBy(f.date)
692
+ return `- ${route} ${f.date} 车次${f.flight_no ? ` ${f.flight_no}` : ''}:**未确认/当前不可售**——exact-date 源 ${f.source} 于 ${f.fetched_at.slice(0, 10)} 返回 0 条;到 ${review} 复核,不得用历史班期/相邻日期填充 ${evidence}`
693
+ }
694
+ if (f.kind === 'train' && f.bookability !== 'bookable_exact_date') {
695
+ return `- ${route} ${f.date} 车次${f.flight_no ? ` ${f.flight_no}` : ''}:**未核验**(${f.bookability})——仅作参考,不得作为可下单方案呈现 ${evidence}`
696
+ }
541
697
  if (f.bookability === 'unavailable_exact_date') {
542
698
  const review = f.review_by ?? defaultReviewBy(f.date)
543
699
  return `- ${route} ${f.date}:**未确认/当前不可售**——exact-date 源 ${f.source} 于 ${f.fetched_at.slice(0, 10)} 返回 0 条;到 ${review} 复核,不得用历史班期/相邻日期填充 ${evidence}`
@@ -545,6 +701,10 @@ function renderFlightFactInner(f: FlightFact): string {
545
701
  if (f.bookability !== 'bookable_exact_date') {
546
702
  return `- ${route} ${f.date} ${f.flight_no || ''}:**未核验**(${f.bookability})——仅作参考,不得作为可下单方案呈现 ${evidence}`
547
703
  }
704
+ if (f.kind === 'train') {
705
+ const times = f.dep_local && f.arr_local ? ` ${f.dep_local}→${f.arr_local}` : ''
706
+ return `- ${route} ${f.date} 车次 ${f.flight_no}${times} ${evidence}`
707
+ }
548
708
  const carrier = f.operating_carrier && f.operating_carrier !== f.marketing_carrier
549
709
  ? `营销 ${f.marketing_carrier ?? '?'} / 实际承运 ${f.operating_carrier}`
550
710
  : (f.marketing_carrier ?? '')
@@ -574,8 +734,24 @@ export function renderConnection(legA: FlightFact, legB: FlightFact): string {
574
734
  /**
575
735
  * 政策事实行:恒为「截至 as_of 的现行政策」表述 + 复核 gate,永不用无条件 ✓。
576
736
  * 远期(出发日晚于 as_of)必须附 review_by(默认 D-30)。
737
+ *
738
+ * 行尾内嵌 `<!-- fact:<fact_id> -->` 锚点(issue #273,ADR-19 typed-anchor 单向生成):
739
+ * 产物经渲染原语生成即自带溯源锚,闸侧锚点确定性回溯;手改/伪造锚点 = fact_anchor_unknown。
740
+ * 与 renderFlightFact / renderHotelFact 同源:启发式 POLICY_WORD 仅覆盖手写/历史产物。
577
741
  */
578
742
  export function renderPolicyFact(p: PolicyFact, tripStart?: string): string {
743
+ return `${policyCanonicalBody(p, tripStart)} <!-- fact:${p.fact_id} -->`
744
+ }
745
+
746
+ /**
747
+ * 政策行 canonical body(不含锚点;issue #359,D-26 残余收口):
748
+ * 闸侧锚点回溯用同一原文,subject/statement/source/fetched_at/query_id 任意一项
749
+ * 改动 → 行文本不再等于 canonical body → fact_anchor_unknown fail-closed。
750
+ * 不走宽松 substring/subset 匹配,避免锚点行被改写 subject/statement 后仍 pass。
751
+ * 复核提醒(review_by 或 tripStart 派生的 defaultReviewBy)是合法的可选段——
752
+ * `tripStart` 与 renderPolicyFact 同一传入,产物与闸两侧语义一致。
753
+ */
754
+ export function policyCanonicalBody(p: PolicyFact, tripStart?: string): string {
579
755
  const review = p.review_by ?? (tripStart ? defaultReviewBy(tripStart) : undefined)
580
756
  const reviewNote = review ? `;远期政策须复核——到 ${review} 再核验一次` : ''
581
757
  return `- ${p.subject}:截至 ${p.as_of} 的现行政策——${p.statement}${reviewNote} [${p.source}@${p.fetched_at} #${p.query_id}]`