@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
@@ -1,40 +1,188 @@
1
- export function mergeProfile(current, patch) {
2
- if (!patch) return null;
1
+ /**
2
+ * T1 动态记忆的合并守门层(M4 记忆域;DeerFlow 研究 T1 落地):
3
+ *
4
+ * 分工(founder 校正「正则匹配 rules 不对」后重写):
5
+ * - 事实提取 = LLM 的活。契约 (18) 已要求模型当轮把对话透露的新事实
6
+ * (预算/日期/窗口/出发地/同伴/实际经历)经 gotry_motivation_save 并入
7
+ * 画像(evidence=用户原话)——语言理解交给模型,不做第二套正则引擎。
8
+ * - 合并守门 = 代码的活。本文件只做三件代码才可靠的事:
9
+ * ① 追加不删史(evidence 永不移除,P0 反幻觉:历史依据不可篡改)
10
+ * ② 幂等(同 evidence 不重复入池)
11
+ * ③ 结构守卫(weights 存在性校验、空补丁拒绝、权重归一)
12
+ *
13
+ * 额外承载(issue #338):用户显式声明的常驻城市/默认出发地——typed
14
+ * homeCity 字段 + 纯函数 resolveDefaultOrigin(explicit origin, profile)。
15
+ * - 当前轮显式出发地永远赢(explicit origin > home city > missing)
16
+ * - homeCity 变更必须伴新 evidence(P0 与 weights/hard 同向);单条 evidence
17
+ * 可作为省略 binding 的兼容形态,多条 evidence 必须显式绑定
18
+ * - 该契约不触碰算术/求解——只读字段,不进 feasibility/evaluate 路径
19
+ *
20
+ * 持久化语义(issue #338):home-city 是 typed self-contained preference
21
+ * 记录 `{ value, evidence, updated_at }`,与全局 evidence 列表解耦——
22
+ * 一次不相关的动机补丁不会改写它的「证据指针」「更新时间」「当前值」。
23
+ * `updated_at` 由调用方在事件边界注入(账本事件行的 ts),mergeProfile
24
+ * 自身不在 fold 路径里再读时钟——保证 rebuildProjections() 与直读投影
25
+ * 永不分叉。
26
+ */
27
+ const ISO_LIKE_TIMESTAMP = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d{1,3})?(Z|[+-]\d{2}:\d{2})$/;
28
+ function isNonBlankString(value) {
29
+ return typeof value === 'string' && value.trim().length > 0;
30
+ }
31
+ function isValidIsoLikeTimestamp(value) {
32
+ if (typeof value !== 'string')
33
+ return false;
34
+ const match = ISO_LIKE_TIMESTAMP.exec(value);
35
+ if (!match)
36
+ return false;
37
+ const year = Number(match[1]);
38
+ const month = Number(match[2]);
39
+ const day = Number(match[3]);
40
+ const hour = Number(match[4]);
41
+ const minute = Number(match[5]);
42
+ const second = Number(match[6]);
43
+ const zone = match[7];
44
+ const daysInMonth = month === 2
45
+ ? (year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : 28)
46
+ : [31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month - 1];
47
+ if (!daysInMonth || day < 1 || day > daysInMonth)
48
+ return false;
49
+ // ISO permits 24:00:00 as the end-of-day spelling; no other 24:xx value.
50
+ if (hour > 23 && !(hour === 24 && minute === 0 && second === 0))
51
+ return false;
52
+ if (minute > 59 || second > 59)
53
+ return false;
54
+ if (zone !== 'Z' && (Number(zone.slice(1, 3)) > 23 || Number(zone.slice(4, 6)) > 59))
55
+ return false;
56
+ return Number.isFinite(Date.parse(value));
57
+ }
58
+ /**
59
+ * Typed home-city preference 的唯一有效性判定。
60
+ * 不读取、不修写 raw profile;raw homeCity 若存在只作镜像一致性校验。
61
+ */
62
+ export function isValidHomeCityPreference(profile) {
63
+ const preference = profile?.homeCityPreference;
64
+ if (!preference || typeof preference !== 'object' || Array.isArray(preference))
65
+ return false;
66
+ const candidate = preference;
67
+ if (!(candidate.value === null || isNonBlankString(candidate.value)))
68
+ return false;
69
+ if (!isNonBlankString(candidate.evidence) || !isValidIsoLikeTimestamp(candidate.updated_at))
70
+ return false;
71
+ if (!profile || !Array.isArray(profile.evidence) || !profile.evidence.some(entry => entry === candidate.evidence))
72
+ return false;
73
+ if (profile && Object.prototype.hasOwnProperty.call(profile, 'homeCity') && profile.homeCity !== candidate.value)
74
+ return false;
75
+ return true;
76
+ }
77
+ /**
78
+ * 合并守门。纯函数;不读时钟——`now` 由调用方从事件边界(appendMotivationPatch
79
+ * 写时 ISO 或 foldEvent 重放时 row.ts)注入,保证写路径与重建路径时间戳一致。
80
+ *
81
+ * 触发 homeCity 操作的同时,会原地维护 typed homeCityPreference:
82
+ * - valid new binding → 新 `{value, evidence: <homeCityEvidence exact string>, updated_at: now}`
83
+ * - unchanged → 沿用 base 的 homeCityPreference(若有);缺失 typed 字段保持缺失
84
+ * - missing/mismatched/stale binding → 返回 null,由账本跳过整次事件
85
+ */
86
+ export function mergeProfile(current, patch, now) {
87
+ if (!patch)
88
+ return null;
3
89
  const base = {
4
- weights: current?.weights ?? {},
5
- evidence: current?.evidence ?? [],
6
- hard: current?.hard ?? {}
7
- };
8
- const newEvidence = (patch.evidence ?? []).filter(Boolean).filter((e)=>!base.evidence.includes(e));
90
+ weights: (current?.weights ?? {}),
91
+ evidence: (current?.evidence ?? []),
92
+ hard: (current?.hard ?? {}),
93
+ homeCity: (current?.homeCity === undefined ? undefined : current.homeCity),
94
+ homeCityPreference: current?.homeCityPreference,
95
+ }; // 首次保存:无档案即空档案
96
+ const newEvidence = (patch.evidence ?? []).filter(Boolean).filter(e => !base.evidence.includes(e));
9
97
  const patchWeights = patch.weights;
10
- const weightsChanged = !!patchWeights && Object.keys(patchWeights).length > 0 && JSON.stringify(patchWeights) !== JSON.stringify(base.weights);
11
- const hardChanged = !!patch.hard && Object.keys(patch.hard).length > 0 && JSON.stringify(patch.hard) !== JSON.stringify(base.hard);
12
- if (newEvidence.length === 0 && !weightsChanged && !hardChanged) return null;
13
- let weights = {
14
- ...base.weights
15
- };
98
+ const weightsChanged = !!patchWeights && Object.keys(patchWeights).length > 0 &&
99
+ JSON.stringify(patchWeights) !== JSON.stringify(base.weights);
100
+ const hardChanged = !!patch.hard && Object.keys(patch.hard).length > 0 &&
101
+ JSON.stringify(patch.hard) !== JSON.stringify(base.hard);
102
+ // homeCity 变更判定:
103
+ // patch.homeCity === undefined → 字段未传,不视为变更
104
+ // string 先 trim;trim 后空白 → 视作「未传」(避免把空白值当清除语义或无意义值写入)
105
+ // trim 后与 base.homeCity 仍不等 → 视为变更(包括 string↔null、null↔undefined 等差异)
106
+ let patchedHomeCityInput = patch.homeCity;
107
+ if (typeof patchedHomeCityInput === 'string') {
108
+ const trimmed = patchedHomeCityInput.trim();
109
+ patchedHomeCityInput = trimmed.length === 0 ? undefined : trimmed;
110
+ }
111
+ const homeCityTouched = patchedHomeCityInput !== undefined;
112
+ const homeCityChanged = homeCityTouched && patchedHomeCityInput !== base.homeCity;
113
+ if (!homeCityTouched && patch.homeCityEvidence !== undefined)
114
+ return null;
115
+ // homeCity 的语义绑定必须在 profile patch 边界明确给出,不从自然语言或
116
+ // evidence 数组位置推断。唯一兼容例外:本次只有一条非空 evidence 时,
117
+ // 该条本身就是 unambiguous binding;多条 evidence 仍必须显式命名。
118
+ let homeCityEvidence;
119
+ let homeCityEvidenceIsNew = false;
120
+ if (homeCityTouched) {
121
+ const evidenceEntries = patch.evidence ?? [];
122
+ const candidate = patch.homeCityEvidence !== undefined
123
+ ? patch.homeCityEvidence
124
+ : evidenceEntries.length === 1 && isNonBlankString(evidenceEntries[0])
125
+ ? evidenceEntries[0]
126
+ : undefined;
127
+ const appearsInCall = isNonBlankString(candidate) && evidenceEntries.some(e => e === candidate);
128
+ homeCityEvidenceIsNew = appearsInCall && !base.evidence.includes(candidate);
129
+ const exactDuplicate = appearsInCall && !homeCityEvidenceIsNew && !homeCityChanged
130
+ && base.homeCityPreference?.value === patchedHomeCityInput
131
+ && base.homeCityPreference?.evidence === candidate;
132
+ if (!appearsInCall || (!homeCityEvidenceIsNew && !exactDuplicate))
133
+ return null;
134
+ homeCityEvidence = candidate;
135
+ }
136
+ // A same-city/clear operation with a new bound quote is a real preference
137
+ // update even though the value itself did not change. The exact duplicate
138
+ // above remains a no-op.
139
+ const homeCityPreferenceChanged = homeCityTouched && homeCityEvidenceIsNew;
140
+ if (newEvidence.length === 0 && !weightsChanged && !hardChanged && !homeCityChanged && !homeCityPreferenceChanged)
141
+ return null;
142
+ // 权重变更必须伴至少一条新 evidence(P0:改画像要有依据),否则拒该部分
143
+ let weights = { ...base.weights };
16
144
  if (weightsChanged && newEvidence.length > 0 && patchWeights) {
17
- weights = {
18
- ...weights,
19
- ...patchWeights
20
- };
21
- const sum = Object.values(weights).reduce((a, b)=>a + b, 0);
22
- if (sum > 0) for (const k of Object.keys(weights))weights[k] = Math.round(weights[k] / sum * 100) / 100;
145
+ weights = { ...weights, ...patchWeights };
146
+ const sum = Object.values(weights).reduce((a, b) => a + b, 0);
147
+ if (sum > 0)
148
+ for (const k of Object.keys(weights))
149
+ weights[k] = Math.round((weights[k] / sum) * 100) / 100;
150
+ }
151
+ // homeCity 操作只接受上面验证过的 exact homeCityEvidence 绑定;无关 evidence
152
+ // 可以继续追加到全局池,但绝不会成为 homeCityPreference 的语义指针。
153
+ let homeCity = base.homeCity;
154
+ let homeCityPreference = base.homeCityPreference;
155
+ if (homeCityPreferenceChanged) {
156
+ homeCity = patchedHomeCityInput ?? null;
157
+ if (homeCityEvidence !== undefined) {
158
+ homeCityPreference = { value: homeCity, evidence: homeCityEvidence, updated_at: now };
159
+ }
23
160
  }
24
161
  return {
25
162
  weights,
26
- evidence: [
27
- ...base.evidence,
28
- ...newEvidence
29
- ],
30
- hard: hardChanged ? {
31
- ...base.hard,
32
- ...patch.hard ?? {}
33
- } : {
34
- ...base.hard
35
- }
163
+ evidence: [...base.evidence, ...newEvidence],
164
+ hard: hardChanged ? { ...base.hard, ...(patch.hard ?? {}) } : { ...base.hard },
165
+ homeCity,
166
+ homeCityPreference,
36
167
  };
37
168
  }
38
-
39
-
40
- //# sourceURL=ts/src/memory-capture.ts
169
+ export function resolveDefaultOrigin(currentTripOrigin, profile) {
170
+ const trimmed = typeof currentTripOrigin === 'string' ? currentTripOrigin.trim() : '';
171
+ const validTypedPreference = isValidHomeCityPreference(profile);
172
+ const preference = validTypedPreference ? profile?.homeCityPreference : undefined;
173
+ const typedValue = preference?.value;
174
+ const homeCity = validTypedPreference ? typedValue : undefined;
175
+ if (trimmed) {
176
+ return { origin: trimmed, source: 'explicit', homeCity, homeCityPreferenceSource: 'none' };
177
+ }
178
+ if (validTypedPreference && typeof typedValue === 'string') {
179
+ return {
180
+ origin: typedValue.trim(),
181
+ source: 'home_default',
182
+ homeCity,
183
+ homeCityEvidence: [preference.evidence],
184
+ homeCityPreferenceSource: 'typed',
185
+ };
186
+ }
187
+ return { origin: null, source: 'missing', homeCity, homeCityPreferenceSource: 'none' };
188
+ }
@@ -1,31 +1,47 @@
1
+ /**
2
+ * 时间窗衰减原语(memory-design P3):行为偏好的新鲜度置信度——
3
+ * 30/90/180/365d 分级窗口,确定性纯函数;**只降不删**(历史事件永远在,
4
+ * 衰减只作用于读时置信度);地板 0.1(记忆永不因旧而消失)。
5
+ *
6
+ * 边界(memory-design §4 P3):衰减只作用于**行为事件**(效用 sidecar 等);
7
+ * 动机权重层零衰减——动机跨年稳定是产品设计 §4 的明文(个性化的锚点),
8
+ * 本模块不提供任何作用于 motivation-profile 的 API(构造性保证)。
9
+ *
10
+ * 未来消费方(行为偏好层落地时):同原语直接复用,窗口即配置。
11
+ */
12
+ /** 分级窗口:age(天)→ 因子;单调不增,地板 0.1(只降不删) */
1
13
  export function windowFactor(ageDays) {
2
- if (ageDays <= 30) return 1.0;
3
- if (ageDays <= 90) return 0.75;
4
- if (ageDays <= 180) return 0.5;
5
- if (ageDays <= 365) return 0.25;
14
+ if (ageDays <= 30)
15
+ return 1.0;
16
+ if (ageDays <= 90)
17
+ return 0.75;
18
+ if (ageDays <= 180)
19
+ return 0.5;
20
+ if (ageDays <= 365)
21
+ return 0.25;
6
22
  return 0.1;
7
23
  }
8
- export const KIND_WEIGHT = {
9
- recalled: 0.25,
10
- applied: 0.5,
11
- verified_outcome: 1.0
12
- };
24
+ /** 事件种类权重:verified_outcome 最强,recalled 最弱(自称被召回 ≠ 有用) */
25
+ export const KIND_WEIGHT = { recalled: 0.25, applied: 0.5, verified_outcome: 1.0 };
13
26
  export function ageDaysOf(ts, now) {
14
27
  const then = new Date(ts).getTime();
15
- if (Number.isNaN(then)) return Number.POSITIVE_INFINITY;
28
+ if (Number.isNaN(then))
29
+ return Number.POSITIVE_INFINITY;
16
30
  return Math.max(0, (now.getTime() - then) / 86_400_000);
17
31
  }
32
+ /** 单事件衰减分:KIND_WEIGHT × windowFactor;未知时间戳按地板(不猜) */
18
33
  export function eventDecayScore(ev, now) {
19
34
  const w = KIND_WEIGHT[ev.kind] ?? 0;
20
35
  return round4(w * windowFactor(ageDaysOf(ev.ts, now)));
21
36
  }
37
+ /**
38
+ * 单条记忆的新鲜置信度 ∈ [0,1]:Σ 事件衰减分,上界 1。
39
+ * 同 wish 同窗口内事件越多置信越高(有界);旧事件只做地板贡献。
40
+ */
22
41
  export function decayedConfidence(events, now) {
23
- const sum = events.reduce((acc, ev)=>acc + eventDecayScore(ev, now), 0);
42
+ const sum = events.reduce((acc, ev) => acc + eventDecayScore(ev, now), 0);
24
43
  return round4(Math.min(1, sum));
25
44
  }
26
45
  function round4(x) {
27
46
  return Math.round(x * 10_000) / 10_000;
28
47
  }
29
-
30
-
31
- //# sourceURL=ts/src/memory-decay.ts