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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (506) hide show
  1. package/README.md +172 -217
  2. package/README.zh-CN.md +222 -0
  3. package/bin/gotry-backend.js +53 -0
  4. package/bin/gotry-booking-copilot.js +53 -0
  5. package/bin/gotry-bootstrap.js +1744 -0
  6. package/bin/gotry-inner.js +733 -83
  7. package/bin/gotry-process-liveness.d.ts +27 -0
  8. package/bin/gotry-process-liveness.js +97 -0
  9. package/bin/gotry-runtime-resolution.d.ts +27 -0
  10. package/bin/gotry-runtime-resolution.js +49 -0
  11. package/bin/gotry.js +1 -1
  12. package/client/client.js +203 -0
  13. package/cordis.gotry-patch.yml +80 -49
  14. package/data/airline-airports.json +39 -0
  15. package/data/stations-12306-verify.json +524 -0
  16. package/dist/capabilities/agent-reach-deep.js +45 -122
  17. package/dist/capabilities/agent-reach.js +101 -146
  18. package/dist/capabilities/anything.js +135 -94
  19. package/dist/capabilities/artifacts.js +370 -0
  20. package/dist/capabilities/channel-health.js +131 -0
  21. package/dist/capabilities/channel-registry.js +256 -0
  22. package/dist/capabilities/doctor.js +546 -0
  23. package/dist/capabilities/effect.js +394 -0
  24. package/dist/capabilities/external-event.js +149 -0
  25. package/dist/capabilities/fact-log.js +55 -0
  26. package/dist/capabilities/flyai-config.js +337 -0
  27. package/dist/capabilities/flyai.js +968 -0
  28. package/dist/capabilities/fx-contract.js +293 -0
  29. package/dist/capabilities/geo-atlas.js +246 -0
  30. package/dist/capabilities/ground-transfer.js +509 -0
  31. package/dist/capabilities/hbcli.js +260 -123
  32. package/dist/capabilities/hotelbyte-transaction.js +194 -0
  33. package/dist/capabilities/incident-log.js +131 -61
  34. package/dist/capabilities/itinerary-artifact.js +190 -0
  35. package/dist/capabilities/itinerary-deck-artifact.js +194 -0
  36. package/dist/capabilities/itinerary-deck-export.js +339 -0
  37. package/dist/capabilities/lavish-local.js +924 -0
  38. package/dist/capabilities/model-override.js +38 -0
  39. package/dist/capabilities/opensky.js +54 -43
  40. package/dist/capabilities/resilience.js +191 -0
  41. package/dist/capabilities/session/action-cache.js +126 -0
  42. package/dist/capabilities/session/adapters/ctrip-flight.js +141 -0
  43. package/dist/capabilities/session/adapters/ctrip-hotel.js +222 -0
  44. package/dist/capabilities/session/adapters/dida-portal.js +274 -0
  45. package/dist/capabilities/session/adapters/meituan-local.js +54 -0
  46. package/dist/capabilities/session/adapters/rail-12306.js +342 -0
  47. package/dist/capabilities/session/benchmark.js +189 -0
  48. package/dist/capabilities/session/bridge-ledger.js +224 -0
  49. package/dist/capabilities/session/extension-bridge.js +636 -0
  50. package/dist/capabilities/session/extension-channel.js +109 -0
  51. package/dist/capabilities/session/extension-distribution.js +230 -0
  52. package/dist/capabilities/session/extract.js +50 -0
  53. package/dist/capabilities/session/golden-score.js +114 -0
  54. package/dist/capabilities/session/health-watch.js +215 -0
  55. package/dist/capabilities/session/read-guard.js +107 -0
  56. package/dist/capabilities/session/static-flight-golden.js +150 -0
  57. package/dist/capabilities/session/transport.js +109 -0
  58. package/dist/capabilities/session/wizard.js +117 -0
  59. package/dist/capabilities/session-consent.js +178 -0
  60. package/dist/capabilities/session-login.js +170 -0
  61. package/dist/capabilities/session-search.js +686 -0
  62. package/dist/capabilities/spawn-bounded.js +203 -0
  63. package/dist/capabilities/sponsor-plugin.js +341 -0
  64. package/dist/capabilities/visa-policy.js +140 -0
  65. package/dist/capabilities/weather.js +243 -138
  66. package/dist/data/session-golden-20.json +25 -0
  67. package/dist/data/sf-golden-manifest.json +103 -0
  68. package/dist/data/sf-static-routes.json +91 -0
  69. package/dist/scripts/action-cache-tests.js +72 -0
  70. package/dist/scripts/agent-planning-turn-deadline-e2e.js +242 -0
  71. package/dist/scripts/agent-planning-turn-deadline-tests.js +185 -0
  72. package/dist/scripts/agent-reach-deep-tests.js +30 -40
  73. package/dist/scripts/agent-reach-error-tests.js +354 -0
  74. package/dist/scripts/agent-reach-tests.js +26 -18
  75. package/dist/scripts/agent-reach-wrapper-tests.js +50 -50
  76. package/dist/scripts/anything-tests.js +116 -60
  77. package/dist/scripts/artifact-client-contract-tests.js +220 -0
  78. package/dist/scripts/artifacts-capability-tests.js +727 -0
  79. package/dist/scripts/async-collect.js +68 -10
  80. package/dist/scripts/benchmark-environment-bridge-e2e.js +741 -0
  81. package/dist/scripts/benchmark-environment-bridge-tests.js +1452 -0
  82. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +126 -0
  83. package/dist/scripts/booking-copilot-availability-policy-tests.js +265 -0
  84. package/dist/scripts/booking-copilot-bin-proof-tests.js +66 -0
  85. package/dist/scripts/booking-copilot-cleanup-proof-helper.js +76 -0
  86. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +144 -0
  87. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +424 -0
  88. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +2839 -0
  89. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +309 -0
  90. package/dist/scripts/booking-copilot-dsh-readiness-proof.js +238 -0
  91. package/dist/scripts/booking-copilot-dsh-warmer-proof.js +123 -0
  92. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +156 -0
  93. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +70 -0
  94. package/dist/scripts/booking-copilot-intent-proof-tests.js +422 -0
  95. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +184 -0
  96. package/dist/scripts/booking-copilot-planner-live-probe.js +95 -0
  97. package/dist/scripts/booking-copilot-proof-runtime.js +42 -0
  98. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +210 -0
  99. package/dist/scripts/booking-copilot-runtime-proof-tests.js +2349 -0
  100. package/dist/scripts/booking-copilot-server-proof-tests.js +784 -0
  101. package/dist/scripts/booking-copilot-startup-proof-tests.js +94 -0
  102. package/dist/scripts/booking-executor-tests.js +80 -0
  103. package/dist/scripts/booking-recovery-chain-tests.js +182 -0
  104. package/dist/scripts/booking-saga-tests.js +125 -0
  105. package/dist/scripts/booking-surface-contract-proof-tests.js +212 -0
  106. package/dist/scripts/bootstrap-tests.js +1479 -0
  107. package/dist/scripts/bridge-events-tests.js +239 -0
  108. package/dist/scripts/bridge-ledger-tests.js +428 -0
  109. package/dist/scripts/build-changelog.js +238 -0
  110. package/dist/scripts/build-metrics-report.js +331 -0
  111. package/dist/scripts/changelog-tests.js +118 -0
  112. package/dist/scripts/channel-probe-tests.js +103 -0
  113. package/dist/scripts/channel-probe.js +169 -0
  114. package/dist/scripts/channel-registry-tests.js +208 -0
  115. package/dist/scripts/companion-tests.js +67 -0
  116. package/dist/scripts/dida-cookie-probe.js +87 -0
  117. package/dist/scripts/dida-runner-stop-tests.js +311 -0
  118. package/dist/scripts/dida-sw-probe.js +114 -0
  119. package/dist/scripts/diff-test.js +17 -12
  120. package/dist/scripts/doctor-tests.js +564 -0
  121. package/dist/scripts/dsh-artifact-e2e.js +279 -0
  122. package/dist/scripts/dsh-artifact-web-e2e.js +675 -0
  123. package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
  124. package/dist/scripts/dsh-runtime-closure-tests.js +182 -0
  125. package/dist/scripts/dsh-runtime-closure.js +162 -0
  126. package/dist/scripts/dsh-session-v3-migration-proof.js +109 -0
  127. package/dist/scripts/dsh-subprocess-local-proof.js +150 -0
  128. package/dist/scripts/dsh-target-closure-proof.js +178 -0
  129. package/dist/scripts/effect-tests.js +539 -0
  130. package/dist/scripts/engine-run.js +1 -3
  131. package/dist/scripts/engine-tests.js +16 -10
  132. package/dist/scripts/evaluation-cadence-tests.js +174 -0
  133. package/dist/scripts/evaluation-contract-tests.js +268 -0
  134. package/dist/scripts/extension-distribution-cli.js +39 -0
  135. package/dist/scripts/extension-distribution-tests.js +443 -0
  136. package/dist/scripts/extension-tests.js +988 -0
  137. package/dist/scripts/external-event-tests.js +350 -0
  138. package/dist/scripts/fact-gate-tests.js +869 -0
  139. package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
  140. package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
  141. package/dist/scripts/flight-malformed-tests.js +159 -0
  142. package/dist/scripts/flyai-setup-tests.js +228 -0
  143. package/dist/scripts/flyai-setup-tool-tests.js +54 -0
  144. package/dist/scripts/flyai-tests.js +692 -0
  145. package/dist/scripts/flyai-tool-registration-contract-tests.js +91 -0
  146. package/dist/scripts/fx-contract-tests.js +201 -0
  147. package/dist/scripts/g5-guard-tests.js +131 -0
  148. package/dist/scripts/g5-guard.js +189 -0
  149. package/dist/scripts/gen-lunar-anchors.js +106 -0
  150. package/dist/scripts/geo-atlas-tests.js +283 -0
  151. package/dist/scripts/gotry-backend-kernel-tests.js +206 -0
  152. package/dist/scripts/gotry-try-demo-tests.js +79 -0
  153. package/dist/scripts/gotry-try-demo.js +49 -0
  154. package/dist/scripts/ground-transfer-tests.js +956 -0
  155. package/dist/scripts/hbcli-e2e-tests.js +159 -0
  156. package/dist/scripts/hbcli-live-optin-tests.js +96 -0
  157. package/dist/scripts/hbcli-release-contract-tests.js +122 -0
  158. package/dist/scripts/hbcli-tests.js +121 -69
  159. package/dist/scripts/health-watch-cli.js +73 -0
  160. package/dist/scripts/hotel-date-gate-tests.js +496 -0
  161. package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
  162. package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
  163. package/dist/scripts/i18n-tests.js +41 -0
  164. package/dist/scripts/incident-tests.js +281 -87
  165. package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
  166. package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
  167. package/dist/scripts/issue-271-liveness-tests.js +569 -0
  168. package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
  169. package/dist/scripts/issue-289-model-retry-tests.js +441 -0
  170. package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
  171. package/dist/scripts/issue-338-home-city-e2e.js +577 -0
  172. package/dist/scripts/issue343-real-entry-e2e.js +160 -0
  173. package/dist/scripts/issue436-persisted-routing-e2e.js +247 -0
  174. package/dist/scripts/itinerary-artifact-tests.js +368 -0
  175. package/dist/scripts/itinerary-deck-artifact-tests.js +416 -0
  176. package/dist/scripts/itinerary-deck-export-tests.js +552 -0
  177. package/dist/scripts/itinerary-deck-tests.js +435 -0
  178. package/dist/scripts/itinerary-html-tests.js +426 -0
  179. package/dist/scripts/journey-tests.js +22 -27
  180. package/dist/scripts/kernel-manifest-evidence.js +109 -0
  181. package/dist/scripts/kernel-manifest-gate.js +126 -0
  182. package/dist/scripts/kernel-manifest-tests.js +212 -0
  183. package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
  184. package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
  185. package/dist/scripts/kernel-manifest.js +369 -0
  186. package/dist/scripts/lavish-local-tests.js +1226 -0
  187. package/dist/scripts/lavish-product-tools-tests.js +537 -0
  188. package/dist/scripts/ledger-repair-apply-tests.js +316 -0
  189. package/dist/scripts/ledger-repair-plan-tests.js +375 -0
  190. package/dist/scripts/ledger-tests.js +480 -0
  191. package/dist/scripts/ledger-workflow-crash.js +32 -0
  192. package/dist/scripts/managed-dsh-cleanup-diagnostic-proof.js +184 -0
  193. package/dist/scripts/managed-dsh-close-failure-proof.js +172 -0
  194. package/dist/scripts/managed-dsh-run-port-proof.js +153 -0
  195. package/dist/scripts/managed-dsh-terminal-proof.js +252 -0
  196. package/dist/scripts/map-tools-vendor-package-proof.js +365 -0
  197. package/dist/scripts/memory-capture-tests.js +242 -61
  198. package/dist/scripts/memory-decay-tests.js +49 -0
  199. package/dist/scripts/memory-lifecycle-tests.js +657 -0
  200. package/dist/scripts/memory-lifecycle.js +196 -0
  201. package/dist/scripts/memory-metrics.js +29 -31
  202. package/dist/scripts/memory-value-report.js +631 -0
  203. package/dist/scripts/memory-value-tests.js +328 -0
  204. package/dist/scripts/metrics-report-tests.js +151 -0
  205. package/dist/scripts/model-override-e2e.js +137 -0
  206. package/dist/scripts/nightly-evidence-tests.js +161 -0
  207. package/dist/scripts/nightly-evidence.js +286 -0
  208. package/dist/scripts/nudge-digest.js +43 -42
  209. package/dist/scripts/observability-tests.js +381 -0
  210. package/dist/scripts/onboarding-tests.js +161 -0
  211. package/dist/scripts/opensky-check.js +18 -13
  212. package/dist/scripts/opensky-tests.js +28 -28
  213. package/dist/scripts/persona-surface-guard-tests.js +49 -0
  214. package/dist/scripts/pnpm-dsh-closure-proof.js +17 -0
  215. package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
  216. package/dist/scripts/price-drift-tests.js +340 -0
  217. package/dist/scripts/price-drift-watch.js +447 -0
  218. package/dist/scripts/probe-poi-tests.js +53 -45
  219. package/dist/scripts/product-metrics.js +483 -0
  220. package/dist/scripts/publish-preverify.js +110 -0
  221. package/dist/scripts/realtime-pricing-tests.js +76 -0
  222. package/dist/scripts/recall-tests.js +513 -0
  223. package/dist/scripts/replay-async.js +20 -18
  224. package/dist/scripts/replay-real.js +18 -18
  225. package/dist/scripts/replay.js +52 -82
  226. package/dist/scripts/session-attach-diagnose.js +31 -0
  227. package/dist/scripts/session-attach-poc.js +62 -0
  228. package/dist/scripts/session-benchmark.js +180 -0
  229. package/dist/scripts/session-dida-live-e2e.js +199 -0
  230. package/dist/scripts/session-extract-tests.js +60 -0
  231. package/dist/scripts/session-link-tests.js +478 -0
  232. package/dist/scripts/session-login.js +29 -0
  233. package/dist/scripts/session-tests.js +862 -0
  234. package/dist/scripts/session-zones-tests.js +358 -0
  235. package/dist/scripts/sf-live-benchmark.js +367 -0
  236. package/dist/scripts/sf-live-challenge-stop-tests.js +453 -0
  237. package/dist/scripts/sf-live-cli-tests.js +92 -0
  238. package/dist/scripts/sf-live-options.js +46 -0
  239. package/dist/scripts/sf-manifest-tests.js +30 -0
  240. package/dist/scripts/sf-manifest.js +33 -0
  241. package/dist/scripts/sf-soft-score-tests.js +67 -0
  242. package/dist/scripts/sf-summary-tests.js +324 -0
  243. package/dist/scripts/sf-summary.js +525 -0
  244. package/dist/scripts/share-tests.js +432 -0
  245. package/dist/scripts/skeleton-check.js +16 -14
  246. package/dist/scripts/skeleton-integration-test.js +28 -11
  247. package/dist/scripts/skills-contract-tests.js +51 -46
  248. package/dist/scripts/smoke-session-gate-tests.js +21 -0
  249. package/dist/scripts/smoke.js +703 -219
  250. package/dist/scripts/spawn-bounded-abort-tests.js +241 -0
  251. package/dist/scripts/sponsor-reuse-tests.js +262 -0
  252. package/dist/scripts/state-cli-tests.js +261 -0
  253. package/dist/scripts/state-cli.js +585 -0
  254. package/dist/scripts/state-repair-cli.js +66 -0
  255. package/dist/scripts/state-repair-tests.js +140 -0
  256. package/dist/scripts/static-golden-tests.js +165 -0
  257. package/dist/scripts/time-eval-tests.js +210 -192
  258. package/dist/scripts/travel-timeline-tests.js +59 -0
  259. package/dist/scripts/turn-handoff-collect-tests.js +169 -0
  260. package/dist/scripts/turn-handoff-collect.js +161 -0
  261. package/dist/scripts/turn-policy-tests.js +55 -0
  262. package/dist/scripts/typed-contract-canary.js +176 -0
  263. package/dist/scripts/tz-resolver-sanity.js +50 -0
  264. package/dist/scripts/tz-resolver-tests.js +584 -0
  265. package/dist/scripts/unified-tests.js +23 -19
  266. package/dist/scripts/visa-policy-tests.js +62 -0
  267. package/dist/scripts/weather-tests.js +276 -41
  268. package/dist/scripts/wish-channel-gate-tests.js +54 -0
  269. package/dist/scripts/write-gate-tests.js +522 -0
  270. package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
  271. package/dist/scripts/z3-lifecycle-tests.js +170 -0
  272. package/dist/scripts/z3-race-repeat-tests.js +39 -0
  273. package/dist/scripts/z3-race-tests.js +41 -0
  274. package/dist/src/artifact-gate.js +829 -0
  275. package/dist/src/backend/kernel.js +91 -0
  276. package/dist/src/backend/modules/booking-copilot.js +92 -0
  277. package/dist/src/backend/modules/booking-executor.js +124 -0
  278. package/dist/src/backend/modules/session-search.js +551 -0
  279. package/dist/src/benchmark-agent-conformance.js +578 -0
  280. package/dist/src/benchmark-environment-bridge.js +515 -0
  281. package/dist/src/benchmark-headless-child-diagnostics.js +166 -0
  282. package/dist/src/benchmark-tool-isolation.js +151 -0
  283. package/dist/src/bookable-facts.js +533 -0
  284. package/dist/src/booking-saga.js +97 -0
  285. package/dist/src/booking-surface/availability-policy.js +697 -0
  286. package/dist/src/booking-surface/booking-intent.js +43 -0
  287. package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
  288. package/dist/src/booking-surface/canonical-schema.js +116 -0
  289. package/dist/src/booking-surface/contracts.js +75 -0
  290. package/dist/src/booking-surface/dsh-planner.js +1854 -0
  291. package/dist/src/booking-surface/dsh-plugin.js +378 -0
  292. package/dist/src/booking-surface/dsh-worker.js +98 -0
  293. package/dist/src/booking-surface/error-codes.js +231 -0
  294. package/dist/src/booking-surface/index.js +9 -0
  295. package/dist/src/booking-surface/managed-dsh-cleanup-diagnostic.js +97 -0
  296. package/dist/src/booking-surface/managed-dsh-run-port.js +244 -0
  297. package/dist/src/booking-surface/profile.js +24 -0
  298. package/dist/src/booking-surface/recovery-chain.js +367 -0
  299. package/dist/src/booking-surface/runtime.js +1968 -0
  300. package/dist/src/booking-surface/server.js +674 -0
  301. package/dist/src/booking-surface/startup.js +168 -0
  302. package/dist/src/booking-surface/validation.js +261 -0
  303. package/dist/src/bridge.js +20 -13
  304. package/dist/src/companions.js +86 -0
  305. package/dist/src/contracts.js +21 -43
  306. package/dist/src/dsh-llm.js +97 -111
  307. package/dist/src/engine.js +276 -193
  308. package/dist/src/evaluation-cadence.js +97 -0
  309. package/dist/src/evaluation-contracts.js +283 -0
  310. package/dist/src/flight-pack-adapter.js +54 -0
  311. package/dist/src/flight-pack-contract.js +2 -0
  312. package/dist/src/flyai-setup-tool.js +70 -0
  313. package/dist/src/gotry-backend.js +125 -0
  314. package/dist/src/hotel-date-gate.js +118 -0
  315. package/dist/src/i18n.js +88 -0
  316. package/dist/src/index.js +2305 -731
  317. package/dist/src/itinerary-deck.js +139 -0
  318. package/dist/src/itinerary-doc-shared.js +661 -0
  319. package/dist/src/itinerary-html.js +131 -0
  320. package/dist/src/journey.js +155 -108
  321. package/dist/src/lavish-tools.js +400 -0
  322. package/dist/src/ledger-repair-apply.js +538 -0
  323. package/dist/src/ledger-repair-plan.js +463 -0
  324. package/dist/src/loop.js +358 -162
  325. package/dist/src/memory-capture.js +180 -32
  326. package/dist/src/memory-decay.js +47 -0
  327. package/dist/src/memory-lifecycle.js +1310 -0
  328. package/dist/src/memory-utility.js +27 -40
  329. package/dist/src/mock-llm.js +36 -61
  330. package/dist/src/model.js +81 -36
  331. package/dist/src/realtime-pricing.js +103 -0
  332. package/dist/src/recall/card.js +74 -0
  333. package/dist/src/recall/evaluator.js +140 -0
  334. package/dist/src/recall/integration.js +17 -0
  335. package/dist/src/recall/tick.js +166 -0
  336. package/dist/src/session-link/plan-it-action.js +48 -0
  337. package/dist/src/session-link/session-link.js +248 -0
  338. package/dist/src/session-zones.js +507 -0
  339. package/dist/src/share/adapters.js +51 -0
  340. package/dist/src/share/share-consent.js +76 -0
  341. package/dist/src/share/share-deck.js +58 -0
  342. package/dist/src/share/share-token.js +146 -0
  343. package/dist/src/slot-spec.js +84 -106
  344. package/dist/src/state-ledger.js +767 -0
  345. package/dist/src/state-repair.js +299 -0
  346. package/dist/src/subagent-job-id-guard.js +58 -0
  347. package/dist/src/time-anchor.js +231 -33
  348. package/dist/src/tool-packet.js +20 -8
  349. package/dist/src/travel-slots.js +58 -35
  350. package/dist/src/travel-timeline.js +59 -0
  351. package/dist/src/turn-deadline.js +287 -0
  352. package/dist/src/turn-policy.js +118 -0
  353. package/dist/src/tz-resolver.js +143 -0
  354. package/dist/src/unified.js +538 -360
  355. package/dist/src/wish-pool.js +42 -12
  356. package/dist/src/write-gate.js +495 -0
  357. package/dist/src/z3-shared.js +284 -0
  358. package/extension/README.md +21 -0
  359. package/extension/README.zh-CN.md +21 -0
  360. package/extension/background.js +463 -0
  361. package/extension/content-bridge.js +270 -0
  362. package/extension/content-main.js +111 -0
  363. package/extension/manifest.json +60 -0
  364. package/package.json +407 -14
  365. package/schemas/booking.intent.schema.json +193 -0
  366. package/schemas/booking.surface.schema.json +2622 -0
  367. package/ts/capabilities/agent-reach-deep.ts +114 -0
  368. package/ts/capabilities/agent-reach.ts +198 -0
  369. package/ts/capabilities/anything.ts +255 -0
  370. package/ts/capabilities/artifacts.ts +428 -0
  371. package/ts/capabilities/fact-log.ts +54 -0
  372. package/ts/capabilities/flyai-config.ts +388 -0
  373. package/ts/capabilities/flyai.ts +1274 -0
  374. package/ts/capabilities/hbcli.ts +253 -71
  375. package/ts/capabilities/incident-log.ts +88 -59
  376. package/ts/capabilities/itinerary-artifact.ts +214 -0
  377. package/ts/capabilities/itinerary-deck-artifact.ts +218 -0
  378. package/ts/capabilities/itinerary-deck-export.ts +378 -0
  379. package/ts/capabilities/opensky.ts +121 -0
  380. package/ts/capabilities/session/action-cache.ts +148 -0
  381. package/ts/capabilities/session/adapters/ctrip-flight.ts +181 -0
  382. package/ts/capabilities/session/adapters/ctrip-hotel.ts +238 -0
  383. package/ts/capabilities/session/adapters/dida-portal.ts +338 -0
  384. package/ts/capabilities/session/adapters/meituan-local.ts +70 -0
  385. package/ts/capabilities/session/adapters/rail-12306.ts +392 -0
  386. package/ts/capabilities/session/benchmark.ts +276 -0
  387. package/ts/capabilities/session/bridge-ledger.ts +333 -0
  388. package/ts/capabilities/session/extension-bridge.ts +794 -0
  389. package/ts/capabilities/session/extension-channel.ts +144 -0
  390. package/ts/capabilities/session/extension-distribution.ts +266 -0
  391. package/ts/capabilities/session/extract.ts +54 -0
  392. package/ts/capabilities/session/golden-score.ts +139 -0
  393. package/ts/capabilities/session/health-watch.ts +264 -0
  394. package/ts/capabilities/session/read-guard.ts +141 -0
  395. package/ts/capabilities/session/static-flight-golden.ts +209 -0
  396. package/ts/capabilities/session/transport.ts +146 -0
  397. package/ts/capabilities/session/wizard.ts +140 -0
  398. package/ts/capabilities/session-consent.ts +211 -0
  399. package/ts/capabilities/session-login.ts +208 -0
  400. package/ts/capabilities/session-search.ts +893 -0
  401. package/ts/capabilities/weather.ts +330 -0
  402. package/ts/dsh-runtime/vendor/README.md +68 -0
  403. package/ts/dsh-runtime/vendor/dsh-map-tools/LICENSE +21 -0
  404. package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +405 -0
  405. package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +404 -0
  406. package/ts/dsh-runtime/vendor/dsh-map-tools/client/client.js +1584 -0
  407. package/ts/dsh-runtime/vendor/dsh-map-tools/cordis.patch.yml +5 -0
  408. package/ts/dsh-runtime/vendor/dsh-map-tools/icon.svg +5 -0
  409. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/amap.js +595 -0
  410. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/nominatim.js +63 -0
  411. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/osrm.js +58 -0
  412. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/photon.js +55 -0
  413. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-file.js +87 -0
  414. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-route.js +131 -0
  415. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config.js +16 -0
  416. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/geo.js +232 -0
  417. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js +120 -0
  418. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +40 -0
  419. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/staticmap-route.js +115 -0
  420. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/geocode.js +127 -0
  421. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/poi.js +84 -0
  422. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/routes.js +267 -0
  423. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/amap.d.ts +90 -0
  424. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/nominatim.d.ts +17 -0
  425. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/osrm.d.ts +15 -0
  426. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/photon.d.ts +22 -0
  427. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-file.d.ts +33 -0
  428. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-route.d.ts +23 -0
  429. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config.d.ts +23 -0
  430. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/geo.d.ts +61 -0
  431. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/index.d.ts +18 -0
  432. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +14 -0
  433. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/staticmap-route.d.ts +31 -0
  434. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/geocode.d.ts +11 -0
  435. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/poi.d.ts +9 -0
  436. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/routes.d.ts +75 -0
  437. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/types.d.ts +68 -0
  438. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types.js +16 -0
  439. package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +97 -0
  440. package/ts/package.json +296 -3
  441. package/ts/scripts/async-collect.ts +91 -0
  442. package/ts/scripts/map-tools-vendor-package-proof.ts +404 -0
  443. package/ts/scripts/skeleton-check.ts +1 -1
  444. package/ts/scripts/skeleton-integration-test.ts +23 -1
  445. package/ts/scripts/state-cli.ts +568 -0
  446. package/ts/scripts/turn-handoff-collect.ts +178 -0
  447. package/ts/src/artifact-gate.ts +991 -0
  448. package/ts/src/benchmark-agent-conformance.ts +619 -0
  449. package/ts/src/benchmark-environment-bridge.ts +538 -0
  450. package/ts/src/benchmark-headless-child-diagnostics.ts +184 -0
  451. package/ts/src/benchmark-tool-isolation.ts +166 -0
  452. package/ts/src/bookable-facts.ts +837 -0
  453. package/ts/src/booking-saga.ts +133 -0
  454. package/ts/src/booking-surface/availability-policy.ts +522 -0
  455. package/ts/src/booking-surface/booking-intent.ts +86 -0
  456. package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
  457. package/ts/src/booking-surface/canonical-schema.js +116 -0
  458. package/ts/src/booking-surface/contracts.ts +475 -0
  459. package/ts/src/booking-surface/dsh-planner.ts +1949 -0
  460. package/ts/src/booking-surface/dsh-plugin.js +378 -0
  461. package/ts/src/booking-surface/dsh-worker.ts +110 -0
  462. package/ts/src/booking-surface/error-codes.ts +241 -0
  463. package/ts/src/booking-surface/index.ts +9 -0
  464. package/ts/src/booking-surface/managed-dsh-cleanup-diagnostic.ts +151 -0
  465. package/ts/src/booking-surface/managed-dsh-run-port.ts +273 -0
  466. package/ts/src/booking-surface/profile.ts +42 -0
  467. package/ts/src/booking-surface/recovery-chain.ts +409 -0
  468. package/ts/src/booking-surface/runtime.ts +1793 -0
  469. package/ts/src/booking-surface/server.ts +733 -0
  470. package/ts/src/booking-surface/startup.ts +201 -0
  471. package/ts/src/booking-surface/validation.ts +217 -0
  472. package/ts/src/companions.ts +113 -0
  473. package/ts/src/contracts.ts +13 -3
  474. package/ts/src/dsh-llm.ts +44 -11
  475. package/ts/src/flyai-setup-tool.ts +77 -0
  476. package/ts/src/index.ts +2107 -224
  477. package/ts/src/itinerary-deck.ts +189 -0
  478. package/ts/src/itinerary-doc-shared.ts +741 -0
  479. package/ts/src/itinerary-html.ts +171 -0
  480. package/ts/src/loop.ts +278 -40
  481. package/ts/src/memory-capture.ts +283 -0
  482. package/ts/src/memory-decay.ts +55 -0
  483. package/ts/src/memory-utility.ts +70 -0
  484. package/ts/src/mock-llm.ts +4 -8
  485. package/ts/src/model.ts +88 -2
  486. package/ts/src/recall/card.ts +106 -0
  487. package/ts/src/recall/evaluator.ts +170 -0
  488. package/ts/src/recall/integration.ts +35 -0
  489. package/ts/src/recall/tick.ts +213 -0
  490. package/ts/src/session-link/plan-it-action.ts +78 -0
  491. package/ts/src/session-link/session-link.ts +275 -0
  492. package/ts/src/share/adapters.ts +93 -0
  493. package/ts/src/share/share-consent.ts +105 -0
  494. package/ts/src/share/share-deck.ts +85 -0
  495. package/ts/src/share/share-token.ts +166 -0
  496. package/ts/src/slot-spec.ts +172 -0
  497. package/ts/src/state-ledger.ts +912 -0
  498. package/ts/src/subagent-job-id-guard.ts +72 -0
  499. package/ts/src/time-anchor.ts +338 -0
  500. package/ts/src/tool-packet.ts +32 -0
  501. package/ts/src/travel-slots.ts +219 -0
  502. package/ts/src/travel-timeline.ts +83 -0
  503. package/ts/src/turn-deadline.ts +366 -0
  504. package/ts/src/turn-policy.ts +154 -0
  505. package/ts/src/unified.ts +360 -89
  506. package/ts/src/wish-pool.ts +79 -0
@@ -0,0 +1,1310 @@
1
+ /**
2
+ * Explicit opt-in M4 planning lifecycle observation collector.
3
+ *
4
+ * This module owns the deterministic contract behind scripts/memory-lifecycle.ts:
5
+ * - every subject/flow/evidence identifier is HMAC-SHA256 pseudonymous;
6
+ * - the wait-code vocabulary is frozen at dataset init;
7
+ * - lifecycle events are append-only and idempotent;
8
+ * - exports target the memory-value scorer input contract without claiming source attestation.
9
+ */
10
+ import { createHash, createHmac, randomBytes } from 'node:crypto';
11
+ import { chmodSync, closeSync, constants, existsSync, ftruncateSync, linkSync, lstatSync, mkdirSync, openSync, readFileSync, realpathSync, statSync, truncateSync, unlinkSync, writeSync, } from 'node:fs';
12
+ import { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path';
13
+ export const MEMORY_LIFECYCLE_STORE_SCHEMA = 'memory_lifecycle_observations.v1';
14
+ export const MEMORY_LIFECYCLE_MANIFEST_SCHEMA = 'memory_lifecycle_manifest.v1';
15
+ export const MEMORY_LIFECYCLE_EVENT_SCHEMA = 'memory_lifecycle_event.v1';
16
+ export const MEMORY_VALUE_FIXTURE_SCHEMA = 'memory_value_fixture.v1';
17
+ export const MEMORY_VALUE_SOURCE_REVIEW_SCHEMA = 'memory_value_source_review.v1';
18
+ export const HMAC_REF_PATTERN = /^hmac-sha256:[0-9a-f]{64}$/;
19
+ export const SHA256_PATTERN = /^[0-9a-f]{64}$/;
20
+ export const WAIT_CODE_PATTERN = /^[a-z][a-z0-9_]{0,31}$/;
21
+ export class MemoryLifecycleError extends Error {
22
+ code;
23
+ constructor(code) {
24
+ super(code);
25
+ this.code = code;
26
+ }
27
+ }
28
+ export const systemClock = {
29
+ now: () => new Date(),
30
+ };
31
+ function fail(code) {
32
+ throw new MemoryLifecycleError(code);
33
+ }
34
+ function isObject(value) {
35
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
36
+ }
37
+ function nonEmptyString(value) {
38
+ return typeof value === 'string' && value.trim().length > 0;
39
+ }
40
+ function assertRawLabel(value, limit = 512) {
41
+ if (!nonEmptyString(value))
42
+ fail('invalid_input');
43
+ if (value.length > limit)
44
+ fail('invalid_input');
45
+ if (/[\u0000-\u001f\u007f]/u.test(value))
46
+ fail('invalid_input');
47
+ return value;
48
+ }
49
+ function assertIsoDate(date) {
50
+ const ms = date.getTime();
51
+ if (!Number.isFinite(ms))
52
+ fail('invalid_input');
53
+ return date.toISOString();
54
+ }
55
+ function parseIsoMs(value) {
56
+ const ms = Date.parse(value);
57
+ if (!Number.isFinite(ms))
58
+ fail('invalid_store');
59
+ if (new Date(ms).toISOString() !== value)
60
+ fail('invalid_store');
61
+ return ms;
62
+ }
63
+ function normalizeHmacKey(key) {
64
+ if (!nonEmptyString(key))
65
+ fail('missing_hmac_key');
66
+ const trimmed = key.trim();
67
+ if (trimmed.length < 32)
68
+ fail('invalid_hmac_key');
69
+ if (/[\u0000-\u001f\u007f]/u.test(trimmed))
70
+ fail('invalid_hmac_key');
71
+ return trimmed;
72
+ }
73
+ function normalizeWaitCodes(codes) {
74
+ if (!Array.isArray(codes) || codes.length === 0)
75
+ fail('invalid_input');
76
+ const seen = new Set();
77
+ for (const raw of codes) {
78
+ const code = assertRawLabel(raw, 32);
79
+ if (!WAIT_CODE_PATTERN.test(code))
80
+ fail('invalid_input');
81
+ if (seen.has(code))
82
+ fail('invalid_input');
83
+ seen.add(code);
84
+ }
85
+ return [...seen].sort();
86
+ }
87
+ function assertSourceKind(value) {
88
+ if (value !== 'synthetic_fixture' && value !== 'observed_private')
89
+ fail('invalid_input');
90
+ return value;
91
+ }
92
+ function assertRefluxKind(value) {
93
+ if (value !== 'recalled' && value !== 'verified_outcome')
94
+ fail('invalid_input');
95
+ return value;
96
+ }
97
+ function assertPreferenceConsumer(value) {
98
+ if (value !== 'ranking' && value !== 'explanation')
99
+ fail('invalid_input');
100
+ return value;
101
+ }
102
+ function assertHmacRef(value) {
103
+ if (!nonEmptyString(value) || !HMAC_REF_PATTERN.test(value))
104
+ fail('invalid_store');
105
+ return value;
106
+ }
107
+ function assertEventObject(value) {
108
+ if (!isObject(value))
109
+ fail('invalid_store');
110
+ if (value.schema_version !== MEMORY_LIFECYCLE_EVENT_SCHEMA)
111
+ fail('invalid_store');
112
+ assertHmacRef(value.event_ref);
113
+ if (!nonEmptyString(value.kind))
114
+ fail('invalid_store');
115
+ if (!nonEmptyString(value.occurred_at))
116
+ fail('invalid_store');
117
+ parseIsoMs(value.occurred_at);
118
+ assertHmacRef(value.consent_ref);
119
+ return value;
120
+ }
121
+ function normalizePolicyPath(path) {
122
+ return resolve(path).replace(/\\/g, '/');
123
+ }
124
+ function assertSafePolicyPath(path) {
125
+ const normalized = normalizePolicyPath(path);
126
+ if (normalized === '/' || normalized.endsWith('/.git') || normalized.includes('/.git/'))
127
+ fail('unsafe_state_root');
128
+ if (normalized.endsWith('/ts/dsh-runtime') || normalized.includes('/ts/dsh-runtime/'))
129
+ fail('unsafe_state_root');
130
+ }
131
+ function nearestExistingAncestor(path) {
132
+ let current = resolve(path);
133
+ for (;;) {
134
+ if (existsSync(current))
135
+ return current;
136
+ const parent = dirname(current);
137
+ if (parent === current)
138
+ return current;
139
+ current = parent;
140
+ }
141
+ }
142
+ function realpathOrUnsafe(path) {
143
+ try {
144
+ return realpathSync.native(path);
145
+ }
146
+ catch {
147
+ fail('unsafe_state_root');
148
+ }
149
+ }
150
+ function sameOrChildPath(parent, child) {
151
+ const distance = relative(parent, child);
152
+ return distance === '' || (!distance.startsWith('..') && !isAbsolute(distance));
153
+ }
154
+ function assertSafeStateRoot(stateRoot) {
155
+ if (!nonEmptyString(stateRoot))
156
+ fail('missing_state_root');
157
+ const resolved = resolve(stateRoot);
158
+ assertSafePolicyPath(resolved);
159
+ assertSafePolicyPath(realpathOrUnsafe(nearestExistingAncestor(resolved)));
160
+ return resolved;
161
+ }
162
+ function assertManagedStoreIsolation(storeRoot) {
163
+ const resolvedStoreRoot = resolve(storeRoot);
164
+ const stateRoot = resolve(resolvedStoreRoot, '..', '..');
165
+ assertSafePolicyPath(stateRoot);
166
+ assertSafePolicyPath(resolvedStoreRoot);
167
+ assertSafePolicyPath(realpathOrUnsafe(nearestExistingAncestor(stateRoot)));
168
+ if (!existsSync(stateRoot)) {
169
+ assertSafePolicyPath(realpathOrUnsafe(nearestExistingAncestor(resolvedStoreRoot)));
170
+ return;
171
+ }
172
+ const stateRootReal = realpathOrUnsafe(stateRoot);
173
+ assertSafePolicyPath(stateRootReal);
174
+ for (const managedPath of [join(stateRoot, 'gotry-state'), resolvedStoreRoot]) {
175
+ const existing = nearestExistingAncestor(managedPath);
176
+ const existingReal = realpathOrUnsafe(existing);
177
+ assertSafePolicyPath(existingReal);
178
+ if (!sameOrChildPath(stateRootReal, existingReal))
179
+ fail('unsafe_state_root');
180
+ }
181
+ }
182
+ function prepareCommon(options) {
183
+ const stateRoot = assertSafeStateRoot(options.stateRoot);
184
+ if (!nonEmptyString(options.consent))
185
+ fail('missing_consent');
186
+ const hmacKey = normalizeHmacKey(options.hmacKey);
187
+ const consent = assertRawLabel(options.consent, 512);
188
+ return {
189
+ consentRef: pseudonymousRef(hmacKey, 'consent', [consent]),
190
+ hmacKey,
191
+ stateRoot,
192
+ storeRoot: join(stateRoot, 'gotry-state', 'memory-lifecycle'),
193
+ };
194
+ }
195
+ export function pseudonymousRef(hmacKey, kind, parts) {
196
+ const key = normalizeHmacKey(hmacKey);
197
+ const hmac = createHmac('sha256', key);
198
+ hmac.update('gotry-memory-lifecycle.v1');
199
+ hmac.update('\0');
200
+ hmac.update(assertRawLabel(kind, 64));
201
+ for (const part of parts) {
202
+ hmac.update('\0');
203
+ hmac.update(assertRawLabel(part, 2048));
204
+ }
205
+ return `hmac-sha256:${hmac.digest('hex')}`;
206
+ }
207
+ export function canonicalJson(value) {
208
+ if (Array.isArray(value))
209
+ return `[${value.map(canonicalJson).join(',')}]`;
210
+ if (isObject(value)) {
211
+ return `{${Object.keys(value).sort().map(key => `${JSON.stringify(key)}:${canonicalJson(value[key])}`).join(',')}}`;
212
+ }
213
+ return JSON.stringify(value);
214
+ }
215
+ export function sha256Hex(value) {
216
+ return createHash('sha256').update(value).digest('hex');
217
+ }
218
+ export function memoryValueSummaryDigest(input) {
219
+ const payload = isObject(input)
220
+ ? Object.fromEntries(Object.entries(input).filter(([key]) => key !== 'source_review'))
221
+ : input;
222
+ return sha256Hex(canonicalJson(payload));
223
+ }
224
+ function eventRef(hmacKey, kind, parts) {
225
+ return pseudonymousRef(hmacKey, `event:${kind}`, parts);
226
+ }
227
+ function subjectRef(hmacKey, subject) {
228
+ return pseudonymousRef(hmacKey, 'subject', [subject]);
229
+ }
230
+ function flowRef(hmacKey, subject, flow) {
231
+ return pseudonymousRef(hmacKey, 'flow', [subjectRef(hmacKey, subject), flow]);
232
+ }
233
+ function waitRef(hmacKey, subject, flow, wait) {
234
+ return pseudonymousRef(hmacKey, 'external-wait', [flowRef(hmacKey, subject, flow), wait]);
235
+ }
236
+ function experienceRef(hmacKey, experience) {
237
+ return pseudonymousRef(hmacKey, 'experience', [experience]);
238
+ }
239
+ function evidenceRef(hmacKey, evidence) {
240
+ return pseudonymousRef(hmacKey, 'evidence', [evidence]);
241
+ }
242
+ function assertionRef(hmacKey, assertion) {
243
+ return pseudonymousRef(hmacKey, 'preference-assertion', [assertion]);
244
+ }
245
+ function datasetRef(hmacKey, dataset) {
246
+ return pseudonymousRef(hmacKey, 'dataset', [dataset]);
247
+ }
248
+ function datasetKeyVerifier(hmacKey) {
249
+ return pseudonymousRef(hmacKey, 'dataset-key-verifier', [MEMORY_LIFECYCLE_STORE_SCHEMA]);
250
+ }
251
+ const OPEN_NOFOLLOW = typeof constants.O_NOFOLLOW === 'number' ? constants.O_NOFOLLOW : 0;
252
+ let tempFileCounter = 0;
253
+ function ensurePrivateDir(path) {
254
+ mkdirSync(path, { recursive: true, mode: 0o700 });
255
+ try {
256
+ chmodSync(path, 0o700);
257
+ }
258
+ catch { /* best effort on non-POSIX filesystems */ }
259
+ }
260
+ function pathExistsByLstat(path) {
261
+ try {
262
+ lstatSync(path);
263
+ return true;
264
+ }
265
+ catch (error) {
266
+ if (isNodeError(error, 'ENOENT'))
267
+ return false;
268
+ fail('unsafe_state_root');
269
+ }
270
+ }
271
+ function assertNoSymlinkLeaf(path) {
272
+ try {
273
+ if (lstatSync(path).isSymbolicLink())
274
+ fail('unsafe_state_root');
275
+ }
276
+ catch (error) {
277
+ if (isNodeError(error, 'ENOENT'))
278
+ return;
279
+ if (error instanceof MemoryLifecycleError)
280
+ throw error;
281
+ fail('unsafe_state_root');
282
+ }
283
+ }
284
+ function assertManagedFilePath(storeRoot, path) {
285
+ const resolvedStoreRoot = resolve(storeRoot);
286
+ const resolvedPath = resolve(path);
287
+ if (!sameOrChildPath(resolvedStoreRoot, resolvedPath))
288
+ fail('unsafe_state_root');
289
+ assertSafePolicyPath(resolvedPath);
290
+ assertManagedStoreIsolation(resolvedStoreRoot);
291
+ const stateRootReal = realpathOrUnsafe(resolve(resolvedStoreRoot, '..', '..'));
292
+ const parentReal = realpathOrUnsafe(nearestExistingAncestor(dirname(resolvedPath)));
293
+ assertSafePolicyPath(parentReal);
294
+ if (!sameOrChildPath(stateRootReal, parentReal))
295
+ fail('unsafe_state_root');
296
+ assertNoSymlinkLeaf(resolvedPath);
297
+ }
298
+ function assertOutputPath(path) {
299
+ const resolvedPath = resolve(path);
300
+ assertSafePolicyPath(resolvedPath);
301
+ const parent = dirname(resolvedPath);
302
+ assertSafePolicyPath(parent);
303
+ assertSafePolicyPath(realpathOrUnsafe(nearestExistingAncestor(parent)));
304
+ if (existsSync(parent))
305
+ assertSafePolicyPath(realpathOrUnsafe(parent));
306
+ return resolvedPath;
307
+ }
308
+ function privateTempPath(path) {
309
+ tempFileCounter += 1;
310
+ return join(dirname(path), `.${basename(path)}.${process.pid}.${Date.now()}.${tempFileCounter}.${randomBytes(6).toString('hex')}.tmp`);
311
+ }
312
+ function writeAllSync(fd, content) {
313
+ const bytes = Buffer.isBuffer(content) ? content : Buffer.from(content);
314
+ let offset = 0;
315
+ while (offset < bytes.length) {
316
+ const written = writeSync(fd, bytes, offset, bytes.length - offset);
317
+ if (!Number.isInteger(written) || written <= 0)
318
+ fail('internal_error');
319
+ offset += written;
320
+ }
321
+ }
322
+ function writePrivateTempFile(path, content) {
323
+ let fd = -1;
324
+ let created = false;
325
+ let caught;
326
+ try {
327
+ fd = openSync(path, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | OPEN_NOFOLLOW, 0o600);
328
+ created = true;
329
+ writeAllSync(fd, content);
330
+ }
331
+ catch (error) {
332
+ caught = error;
333
+ }
334
+ finally {
335
+ if (fd >= 0) {
336
+ try {
337
+ closeSync(fd);
338
+ }
339
+ catch (error) {
340
+ caught ??= error;
341
+ }
342
+ }
343
+ if (caught !== undefined && created) {
344
+ try {
345
+ unlinkSync(path);
346
+ }
347
+ catch { /* best effort temp cleanup */ }
348
+ }
349
+ }
350
+ if (caught !== undefined) {
351
+ if (caught instanceof MemoryLifecycleError)
352
+ throw caught;
353
+ if (isNodeError(caught, 'ELOOP'))
354
+ fail('unsafe_state_root');
355
+ fail('internal_error');
356
+ }
357
+ try {
358
+ chmodSync(path, 0o600);
359
+ }
360
+ catch { /* best effort */ }
361
+ }
362
+ function publishTempNoOverwrite(tempPath, finalPath, existsCode) {
363
+ try {
364
+ linkSync(tempPath, finalPath);
365
+ }
366
+ catch (error) {
367
+ if (isNodeError(error, 'EEXIST'))
368
+ fail(existsCode);
369
+ fail('internal_error');
370
+ }
371
+ }
372
+ function writeManagedFileNoOverwrite(storeRoot, path, content, existsCode) {
373
+ assertManagedFilePath(storeRoot, path);
374
+ ensurePrivateDir(dirname(path));
375
+ assertManagedFilePath(storeRoot, path);
376
+ if (pathExistsByLstat(path))
377
+ fail(existsCode);
378
+ const tempPath = privateTempPath(path);
379
+ let tempCreated = false;
380
+ try {
381
+ assertManagedFilePath(storeRoot, tempPath);
382
+ writePrivateTempFile(tempPath, content);
383
+ tempCreated = true;
384
+ assertManagedFilePath(storeRoot, path);
385
+ publishTempNoOverwrite(tempPath, path, existsCode);
386
+ }
387
+ finally {
388
+ if (tempCreated) {
389
+ try {
390
+ unlinkSync(tempPath);
391
+ }
392
+ catch { /* best effort temp cleanup */ }
393
+ }
394
+ }
395
+ try {
396
+ chmodSync(path, 0o600);
397
+ }
398
+ catch { /* best effort */ }
399
+ }
400
+ function writePrivateFileNoOverwrite(path, content) {
401
+ const finalPath = assertOutputPath(path);
402
+ ensurePrivateDir(dirname(finalPath));
403
+ assertOutputPath(finalPath);
404
+ if (pathExistsByLstat(finalPath))
405
+ fail('output_exists');
406
+ const tempPath = privateTempPath(finalPath);
407
+ let tempCreated = false;
408
+ try {
409
+ assertOutputPath(tempPath);
410
+ writePrivateTempFile(tempPath, content);
411
+ tempCreated = true;
412
+ assertOutputPath(finalPath);
413
+ if (pathExistsByLstat(finalPath))
414
+ fail('output_exists');
415
+ publishTempNoOverwrite(tempPath, finalPath, 'output_exists');
416
+ }
417
+ finally {
418
+ if (tempCreated) {
419
+ try {
420
+ unlinkSync(tempPath);
421
+ }
422
+ catch { /* best effort temp cleanup */ }
423
+ }
424
+ }
425
+ try {
426
+ chmodSync(finalPath, 0o600);
427
+ }
428
+ catch { /* best effort */ }
429
+ }
430
+ function appendPrivateLine(storeRoot, path, line) {
431
+ assertManagedFilePath(storeRoot, path);
432
+ ensurePrivateDir(dirname(path));
433
+ assertManagedFilePath(storeRoot, path);
434
+ const existedBefore = pathExistsByLstat(path);
435
+ const originalSize = existedBefore ? statSync(path).size : 0;
436
+ const payload = `${line}\n`;
437
+ let fd = -1;
438
+ let caught;
439
+ try {
440
+ fd = openSync(path, constants.O_WRONLY | constants.O_CREAT | constants.O_APPEND | OPEN_NOFOLLOW, 0o600);
441
+ writeAllSync(fd, payload);
442
+ }
443
+ catch (error) {
444
+ caught = error;
445
+ if (fd >= 0) {
446
+ try {
447
+ ftruncateSync(fd, originalSize);
448
+ }
449
+ catch { /* keep original error */ }
450
+ }
451
+ }
452
+ finally {
453
+ if (fd >= 0) {
454
+ try {
455
+ closeSync(fd);
456
+ }
457
+ catch { /* close is non-semantic after append/truncate */ }
458
+ }
459
+ if (caught !== undefined && !existedBefore) {
460
+ try {
461
+ unlinkSync(path);
462
+ }
463
+ catch { /* best effort rollback */ }
464
+ }
465
+ }
466
+ if (caught !== undefined) {
467
+ if (caught instanceof MemoryLifecycleError)
468
+ throw caught;
469
+ if (isNodeError(caught, 'ELOOP'))
470
+ fail('unsafe_state_root');
471
+ fail('internal_error');
472
+ }
473
+ try {
474
+ chmodSync(path, 0o600);
475
+ }
476
+ catch { /* best effort */ }
477
+ }
478
+ function isNodeError(error, code) {
479
+ return isObject(error) && error.code === code;
480
+ }
481
+ function withStoreLock(storeRoot, createStore, body) {
482
+ assertManagedStoreIsolation(storeRoot);
483
+ if (createStore)
484
+ ensurePrivateDir(storeRoot);
485
+ else if (!existsSync(storeRoot))
486
+ fail('dataset_not_initialized');
487
+ assertManagedStoreIsolation(storeRoot);
488
+ const lockPath = join(storeRoot, '.writer.lock');
489
+ assertManagedFilePath(storeRoot, lockPath);
490
+ let fd = -1;
491
+ let createdLock = false;
492
+ try {
493
+ fd = openSync(lockPath, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | OPEN_NOFOLLOW, 0o600);
494
+ createdLock = true;
495
+ writeAllSync(fd, JSON.stringify({ schema_version: 'memory_lifecycle_lock.v1', pid: process.pid }));
496
+ }
497
+ catch (error) {
498
+ if (fd >= 0) {
499
+ try {
500
+ closeSync(fd);
501
+ }
502
+ catch { /* preserve original error */ }
503
+ fd = -1;
504
+ }
505
+ if (createdLock) {
506
+ try {
507
+ unlinkSync(lockPath);
508
+ }
509
+ catch { /* best effort for this writer's failed lock */ }
510
+ }
511
+ if (isNodeError(error, 'EEXIST'))
512
+ fail('lock_busy');
513
+ fail('internal_error');
514
+ }
515
+ finally {
516
+ if (fd >= 0)
517
+ closeSync(fd);
518
+ }
519
+ try {
520
+ assertManagedStoreIsolation(storeRoot);
521
+ return body();
522
+ }
523
+ finally {
524
+ try {
525
+ unlinkSync(lockPath);
526
+ }
527
+ catch { /* lock cleanup is best effort */ }
528
+ }
529
+ }
530
+ function manifestPath(storeRoot) {
531
+ return join(storeRoot, 'manifest.json');
532
+ }
533
+ function eventsPath(storeRoot) {
534
+ return join(storeRoot, 'events.jsonl');
535
+ }
536
+ function readManifest(storeRoot) {
537
+ const path = manifestPath(storeRoot);
538
+ assertManagedFilePath(storeRoot, path);
539
+ if (!existsSync(path))
540
+ fail('dataset_not_initialized');
541
+ let parsed;
542
+ try {
543
+ parsed = JSON.parse(readFileSync(path, 'utf8'));
544
+ }
545
+ catch {
546
+ fail('invalid_store');
547
+ }
548
+ return assertManifest(parsed);
549
+ }
550
+ function assertManifest(value) {
551
+ if (!isObject(value))
552
+ fail('invalid_store');
553
+ if (value.schema_version !== MEMORY_LIFECYCLE_MANIFEST_SCHEMA)
554
+ fail('invalid_store');
555
+ if (value.collector_schema !== MEMORY_LIFECYCLE_STORE_SCHEMA)
556
+ fail('invalid_store');
557
+ const ref = assertHmacRef(value.dataset_ref);
558
+ const keyVerifier = assertHmacRef(value.dataset_key_verifier);
559
+ const source = value.source_kind;
560
+ if (source !== 'synthetic_fixture' && source !== 'observed_private')
561
+ fail('invalid_store');
562
+ if (!nonEmptyString(value.created_at))
563
+ fail('invalid_store');
564
+ parseIsoMs(value.created_at);
565
+ const consentRef = assertHmacRef(value.consent_ref);
566
+ if (!isObject(value.measurement_policy))
567
+ fail('invalid_store');
568
+ const policy = value.measurement_policy;
569
+ if (policy.quantile_method !== 'nearest_rank')
570
+ fail('invalid_store');
571
+ if (!Array.isArray(policy.predeclared_external_wait_codes))
572
+ fail('invalid_store');
573
+ const waitCodes = normalizeWaitCodes(policy.predeclared_external_wait_codes.map(String));
574
+ if (policy.minimum_pair_count_for_exit !== 5)
575
+ fail('invalid_store');
576
+ if (policy.target_median_reduction_ratio !== 0.5)
577
+ fail('invalid_store');
578
+ if (!isObject(value.p4) || value.p4.state !== 'closed' || !isObject(value.p4.triggers))
579
+ fail('invalid_store');
580
+ if (value.p4.triggers.real_usage !== false || value.p4.triggers.multi_user !== false)
581
+ fail('invalid_store');
582
+ return {
583
+ schema_version: MEMORY_LIFECYCLE_MANIFEST_SCHEMA,
584
+ collector_schema: MEMORY_LIFECYCLE_STORE_SCHEMA,
585
+ dataset_ref: ref,
586
+ dataset_key_verifier: keyVerifier,
587
+ source_kind: source,
588
+ created_at: value.created_at,
589
+ consent_ref: consentRef,
590
+ measurement_policy: {
591
+ quantile_method: 'nearest_rank',
592
+ predeclared_external_wait_codes: waitCodes,
593
+ minimum_pair_count_for_exit: 5,
594
+ target_median_reduction_ratio: 0.5,
595
+ },
596
+ p4: { state: 'closed', triggers: { real_usage: false, multi_user: false } },
597
+ };
598
+ }
599
+ function readEvents(storeRoot, recoverUncommittedTail = false) {
600
+ const path = eventsPath(storeRoot);
601
+ assertManagedFilePath(storeRoot, path);
602
+ if (!existsSync(path))
603
+ return [];
604
+ let raw;
605
+ try {
606
+ raw = readFileSync(path, 'utf8');
607
+ }
608
+ catch {
609
+ fail('invalid_store');
610
+ }
611
+ if (recoverUncommittedTail)
612
+ raw = recoverCommittedEventLog(storeRoot, path, raw);
613
+ return parseEventLines(raw.split('\n'));
614
+ }
615
+ function recoverCommittedEventLog(storeRoot, path, raw) {
616
+ if (raw === '' || raw.endsWith('\n'))
617
+ return raw;
618
+ const committedLength = raw.lastIndexOf('\n') + 1;
619
+ const committedRaw = raw.slice(0, committedLength);
620
+ parseEventLines(committedRaw.split('\n'));
621
+ const tail = raw.slice(committedLength);
622
+ if (tail.trim() !== '') {
623
+ try {
624
+ parseEventLines([...committedRaw.split('\n').filter(line => line.trim() !== ''), tail]);
625
+ appendPrivateLine(storeRoot, path, '');
626
+ return `${raw}\n`;
627
+ }
628
+ catch (error) {
629
+ if (!(error instanceof MemoryLifecycleError) || error.code !== 'invalid_store')
630
+ throw error;
631
+ }
632
+ }
633
+ try {
634
+ assertManagedFilePath(storeRoot, path);
635
+ truncateSync(path, committedLength);
636
+ }
637
+ catch (error) {
638
+ if (error instanceof MemoryLifecycleError)
639
+ throw error;
640
+ fail('invalid_store');
641
+ }
642
+ return committedRaw;
643
+ }
644
+ function parseEventLines(lines) {
645
+ const events = [];
646
+ const seen = new Map();
647
+ for (const line of lines) {
648
+ if (line.trim() === '')
649
+ continue;
650
+ let parsed;
651
+ try {
652
+ parsed = JSON.parse(line);
653
+ }
654
+ catch {
655
+ fail('invalid_store');
656
+ }
657
+ const event = assertLifecycleEvent(parsed);
658
+ const canonical = canonicalJson(event);
659
+ const prior = seen.get(event.event_ref);
660
+ if (prior !== undefined) {
661
+ if (prior !== canonical)
662
+ fail('invalid_store');
663
+ continue;
664
+ }
665
+ seen.set(event.event_ref, canonical);
666
+ events.push(event);
667
+ }
668
+ return events;
669
+ }
670
+ function assertLifecycleEvent(value) {
671
+ const raw = assertEventObject(value);
672
+ switch (raw.kind) {
673
+ case 'flow_started':
674
+ if (raw.eligible !== true)
675
+ fail('invalid_store');
676
+ return {
677
+ schema_version: MEMORY_LIFECYCLE_EVENT_SCHEMA,
678
+ event_ref: raw.event_ref,
679
+ kind: 'flow_started',
680
+ occurred_at: raw.occurred_at,
681
+ consent_ref: raw.consent_ref,
682
+ subject_ref: assertHmacRef(raw.subject_ref),
683
+ flow_ref: assertHmacRef(raw.flow_ref),
684
+ eligible: true,
685
+ };
686
+ case 'external_wait_started':
687
+ if (!nonEmptyString(raw.code) || !WAIT_CODE_PATTERN.test(raw.code))
688
+ fail('invalid_store');
689
+ return {
690
+ schema_version: MEMORY_LIFECYCLE_EVENT_SCHEMA,
691
+ event_ref: raw.event_ref,
692
+ kind: 'external_wait_started',
693
+ occurred_at: raw.occurred_at,
694
+ consent_ref: raw.consent_ref,
695
+ subject_ref: assertHmacRef(raw.subject_ref),
696
+ flow_ref: assertHmacRef(raw.flow_ref),
697
+ wait_ref: assertHmacRef(raw.wait_ref),
698
+ code: raw.code,
699
+ };
700
+ case 'external_wait_ended':
701
+ return {
702
+ schema_version: MEMORY_LIFECYCLE_EVENT_SCHEMA,
703
+ event_ref: raw.event_ref,
704
+ kind: 'external_wait_ended',
705
+ occurred_at: raw.occurred_at,
706
+ consent_ref: raw.consent_ref,
707
+ subject_ref: assertHmacRef(raw.subject_ref),
708
+ flow_ref: assertHmacRef(raw.flow_ref),
709
+ wait_ref: assertHmacRef(raw.wait_ref),
710
+ };
711
+ case 'flow_completed':
712
+ if (raw.status !== 'completed')
713
+ fail('invalid_store');
714
+ return {
715
+ schema_version: MEMORY_LIFECYCLE_EVENT_SCHEMA,
716
+ event_ref: raw.event_ref,
717
+ kind: 'flow_completed',
718
+ occurred_at: raw.occurred_at,
719
+ consent_ref: raw.consent_ref,
720
+ subject_ref: assertHmacRef(raw.subject_ref),
721
+ flow_ref: assertHmacRef(raw.flow_ref),
722
+ status: 'completed',
723
+ };
724
+ case 'experience_reflux_recorded': {
725
+ const kind = raw.reflux_kind;
726
+ if (kind !== 'recalled' && kind !== 'verified_outcome')
727
+ fail('invalid_store');
728
+ return {
729
+ schema_version: MEMORY_LIFECYCLE_EVENT_SCHEMA,
730
+ event_ref: raw.event_ref,
731
+ kind: 'experience_reflux_recorded',
732
+ occurred_at: raw.occurred_at,
733
+ consent_ref: raw.consent_ref,
734
+ reflux_kind: kind,
735
+ experience_ref: assertHmacRef(raw.experience_ref),
736
+ evidence_ref: assertHmacRef(raw.evidence_ref),
737
+ };
738
+ }
739
+ case 'preference_recorded': {
740
+ const consumer = raw.consumer;
741
+ if (consumer !== 'ranking' && consumer !== 'explanation')
742
+ fail('invalid_store');
743
+ if (raw.hard_filter !== false)
744
+ fail('invalid_store');
745
+ return {
746
+ schema_version: MEMORY_LIFECYCLE_EVENT_SCHEMA,
747
+ event_ref: raw.event_ref,
748
+ kind: 'preference_recorded',
749
+ occurred_at: raw.occurred_at,
750
+ consent_ref: raw.consent_ref,
751
+ assertion_ref: assertHmacRef(raw.assertion_ref),
752
+ evidence_ref: assertHmacRef(raw.evidence_ref),
753
+ consumer,
754
+ hard_filter: false,
755
+ };
756
+ }
757
+ default:
758
+ fail('invalid_store');
759
+ }
760
+ }
761
+ function eventExists(events, ref) {
762
+ return events.some(event => event.event_ref === ref);
763
+ }
764
+ function appendEvent(storeRoot, events, event) {
765
+ assertCandidateProjection(events, event);
766
+ assertManagedStoreIsolation(storeRoot);
767
+ appendPrivateLine(storeRoot, eventsPath(storeRoot), JSON.stringify(event));
768
+ }
769
+ function assertCandidateProjection(events, event) {
770
+ try {
771
+ projectLifecycleEvents([...events, event]);
772
+ }
773
+ catch (error) {
774
+ if (error instanceof MemoryLifecycleError && error.code === 'invalid_store')
775
+ fail('invalid_transition');
776
+ throw error;
777
+ }
778
+ }
779
+ export function projectLifecycleEvents(events) {
780
+ const flows = new Map();
781
+ const flowsBySubject = new Map();
782
+ const refluxEvents = [];
783
+ const preferences = [];
784
+ const refluxKinds = new Set();
785
+ const assertionRefs = new Set();
786
+ for (const event of events) {
787
+ switch (event.kind) {
788
+ case 'flow_started': {
789
+ if (flows.has(event.flow_ref))
790
+ fail('invalid_store');
791
+ const subjectFlows = flowsBySubject.get(event.subject_ref) ?? [];
792
+ if (subjectFlows.some(existing => existing.completedAt === undefined))
793
+ fail('invalid_store');
794
+ const startedAtMs = parseIsoMs(event.occurred_at);
795
+ const lastCompleted = subjectFlows
796
+ .filter(existing => existing.completedAt !== undefined)
797
+ .sort(compareFlows)
798
+ .at(-1);
799
+ if (lastCompleted && startedAtMs <= parseIsoMs(lastCompleted.completedAt))
800
+ fail('invalid_store');
801
+ const flow = {
802
+ subjectRef: event.subject_ref,
803
+ flowRef: event.flow_ref,
804
+ eligible: true,
805
+ startedAt: event.occurred_at,
806
+ waits: new Map(),
807
+ };
808
+ subjectFlows.push(flow);
809
+ flowsBySubject.set(event.subject_ref, subjectFlows);
810
+ flows.set(event.flow_ref, flow);
811
+ break;
812
+ }
813
+ case 'external_wait_started': {
814
+ const flow = flows.get(event.flow_ref);
815
+ if (!flow || flow.subjectRef !== event.subject_ref || flow.completedAt !== undefined)
816
+ fail('invalid_store');
817
+ if (flow.waits.has(event.wait_ref))
818
+ fail('invalid_store');
819
+ if ([...flow.waits.values()].some(wait => wait.completedAt === undefined))
820
+ fail('invalid_store');
821
+ const startedAtMs = parseIsoMs(event.occurred_at);
822
+ if (startedAtMs < parseIsoMs(flow.startedAt))
823
+ fail('invalid_store');
824
+ for (const wait of flow.waits.values()) {
825
+ if (wait.completedAt && startedAtMs < parseIsoMs(wait.completedAt))
826
+ fail('invalid_store');
827
+ }
828
+ flow.waits.set(event.wait_ref, { waitRef: event.wait_ref, code: event.code, startedAt: event.occurred_at });
829
+ break;
830
+ }
831
+ case 'external_wait_ended': {
832
+ const flow = flows.get(event.flow_ref);
833
+ const wait = flow?.waits.get(event.wait_ref);
834
+ if (!flow || flow.subjectRef !== event.subject_ref || flow.completedAt !== undefined || !wait || wait.completedAt !== undefined) {
835
+ fail('invalid_store');
836
+ }
837
+ if (parseIsoMs(event.occurred_at) <= parseIsoMs(wait.startedAt))
838
+ fail('invalid_store');
839
+ wait.completedAt = event.occurred_at;
840
+ break;
841
+ }
842
+ case 'flow_completed': {
843
+ const flow = flows.get(event.flow_ref);
844
+ if (!flow || flow.subjectRef !== event.subject_ref || flow.completedAt !== undefined)
845
+ fail('invalid_store');
846
+ if ([...flow.waits.values()].some(wait => wait.completedAt === undefined))
847
+ fail('invalid_store');
848
+ if (parseIsoMs(event.occurred_at) <= parseIsoMs(flow.startedAt))
849
+ fail('invalid_store');
850
+ const completedAtMs = parseIsoMs(event.occurred_at);
851
+ for (const wait of flow.waits.values()) {
852
+ if (parseIsoMs(wait.startedAt) < parseIsoMs(flow.startedAt) || parseIsoMs(wait.completedAt) > completedAtMs)
853
+ fail('invalid_store');
854
+ }
855
+ flow.completedAt = event.occurred_at;
856
+ break;
857
+ }
858
+ case 'experience_reflux_recorded': {
859
+ const key = `${event.reflux_kind}:${event.experience_ref}`;
860
+ if (refluxKinds.has(key))
861
+ fail('invalid_store');
862
+ refluxKinds.add(key);
863
+ refluxEvents.push({ refluxKind: event.reflux_kind, experienceRef: event.experience_ref, evidenceRef: event.evidence_ref });
864
+ break;
865
+ }
866
+ case 'preference_recorded':
867
+ if (assertionRefs.has(event.assertion_ref))
868
+ fail('invalid_store');
869
+ assertionRefs.add(event.assertion_ref);
870
+ preferences.push({
871
+ assertionRef: event.assertion_ref,
872
+ evidenceRef: event.evidence_ref,
873
+ consumer: event.consumer,
874
+ hardFilter: false,
875
+ });
876
+ break;
877
+ }
878
+ }
879
+ return { flows, flowsBySubject, refluxEvents, preferences };
880
+ }
881
+ function buildManifest(options, common, clock) {
882
+ return {
883
+ schema_version: MEMORY_LIFECYCLE_MANIFEST_SCHEMA,
884
+ collector_schema: MEMORY_LIFECYCLE_STORE_SCHEMA,
885
+ dataset_ref: datasetRef(common.hmacKey, assertRawLabel(options.dataset)),
886
+ dataset_key_verifier: datasetKeyVerifier(common.hmacKey),
887
+ source_kind: assertSourceKind(options.sourceKind),
888
+ created_at: assertIsoDate(clock.now()),
889
+ consent_ref: common.consentRef,
890
+ measurement_policy: {
891
+ quantile_method: 'nearest_rank',
892
+ predeclared_external_wait_codes: normalizeWaitCodes(options.waitCodes),
893
+ minimum_pair_count_for_exit: 5,
894
+ target_median_reduction_ratio: 0.5,
895
+ },
896
+ p4: { state: 'closed', triggers: { real_usage: false, multi_user: false } },
897
+ };
898
+ }
899
+ function sameFrozenDataset(existing, next) {
900
+ return existing.dataset_ref === next.dataset_ref
901
+ && existing.dataset_key_verifier === next.dataset_key_verifier
902
+ && existing.source_kind === next.source_kind
903
+ && existing.consent_ref === next.consent_ref
904
+ && canonicalJson(existing.measurement_policy) === canonicalJson(next.measurement_policy);
905
+ }
906
+ function assertDatasetKeyMatches(manifest, hmacKey) {
907
+ if (manifest.dataset_key_verifier !== datasetKeyVerifier(hmacKey))
908
+ fail('dataset_key_mismatch');
909
+ }
910
+ function assertDatasetConsentMatches(manifest, consentRef) {
911
+ if (manifest.consent_ref !== consentRef)
912
+ fail('dataset_consent_mismatch');
913
+ }
914
+ function assertEventsBelongToDataset(manifest, events) {
915
+ if (events.some(event => event.consent_ref !== manifest.consent_ref))
916
+ fail('invalid_store');
917
+ }
918
+ export function initMemoryLifecycleDataset(options, clock = systemClock) {
919
+ const common = prepareCommon(options);
920
+ const next = buildManifest(options, common, clock);
921
+ return withStoreLock(common.storeRoot, true, () => {
922
+ const path = manifestPath(common.storeRoot);
923
+ if (existsSync(path)) {
924
+ const existing = readManifest(common.storeRoot);
925
+ assertDatasetKeyMatches(existing, common.hmacKey);
926
+ if (existing.source_kind !== next.source_kind)
927
+ fail('dataset_source_mismatch');
928
+ if (existing.consent_ref !== next.consent_ref)
929
+ fail('dataset_consent_mismatch');
930
+ if (!sameFrozenDataset(existing, next))
931
+ fail('dataset_already_initialized');
932
+ return {
933
+ schema: 'memory_lifecycle_cli_result.v1',
934
+ ok: true,
935
+ command: 'init',
936
+ status: 'unchanged',
937
+ dataset_ref: existing.dataset_ref,
938
+ source_kind: existing.source_kind,
939
+ wait_code_count: existing.measurement_policy.predeclared_external_wait_codes.length,
940
+ };
941
+ }
942
+ writeManagedFileNoOverwrite(common.storeRoot, path, `${JSON.stringify(next, null, 2)}\n`, 'dataset_already_initialized');
943
+ return {
944
+ schema: 'memory_lifecycle_cli_result.v1',
945
+ ok: true,
946
+ command: 'init',
947
+ status: 'recorded',
948
+ dataset_ref: next.dataset_ref,
949
+ source_kind: next.source_kind,
950
+ wait_code_count: next.measurement_policy.predeclared_external_wait_codes.length,
951
+ };
952
+ });
953
+ }
954
+ function loadLockedStore(common) {
955
+ const manifest = readManifest(common.storeRoot);
956
+ assertDatasetKeyMatches(manifest, common.hmacKey);
957
+ assertDatasetConsentMatches(manifest, common.consentRef);
958
+ const events = readEvents(common.storeRoot, true);
959
+ assertEventsBelongToDataset(manifest, events);
960
+ return { manifest, events, projection: projectLifecycleEvents(events) };
961
+ }
962
+ function completedSubjectFlows(projection, subject) {
963
+ return (projection.flowsBySubject.get(subject) ?? [])
964
+ .filter(flow => flow.completedAt !== undefined)
965
+ .sort(compareFlows);
966
+ }
967
+ function compareFlows(a, b) {
968
+ return parseIsoMs(a.startedAt) - parseIsoMs(b.startedAt) || parseIsoMs(a.completedAt ?? a.startedAt) - parseIsoMs(b.completedAt ?? b.startedAt) || a.flowRef.localeCompare(b.flowRef);
969
+ }
970
+ function activeSubjectFlow(projection, subject) {
971
+ return (projection.flowsBySubject.get(subject) ?? []).find(flow => flow.completedAt === undefined);
972
+ }
973
+ export function startMemoryLifecycleFlow(options, clock = systemClock) {
974
+ const common = prepareCommon(options);
975
+ const subject = subjectRef(common.hmacKey, assertRawLabel(options.subject));
976
+ const flow = flowRef(common.hmacKey, options.subject, assertRawLabel(options.flow));
977
+ const ref = eventRef(common.hmacKey, 'flow_started', [subject, flow]);
978
+ return withStoreLock(common.storeRoot, false, () => {
979
+ const { events, projection } = loadLockedStore(common);
980
+ if (eventExists(events, ref))
981
+ return eventResult('start', 'unchanged', ref);
982
+ if (activeSubjectFlow(projection, subject))
983
+ fail('invalid_transition');
984
+ if (completedSubjectFlows(projection, subject).length >= 2)
985
+ fail('flow_limit_reached');
986
+ if (projection.flows.has(flow))
987
+ fail('invalid_transition');
988
+ const event = {
989
+ schema_version: MEMORY_LIFECYCLE_EVENT_SCHEMA,
990
+ event_ref: ref,
991
+ kind: 'flow_started',
992
+ occurred_at: assertIsoDate(clock.now()),
993
+ consent_ref: common.consentRef,
994
+ subject_ref: subject,
995
+ flow_ref: flow,
996
+ eligible: true,
997
+ };
998
+ appendEvent(common.storeRoot, events, event);
999
+ return eventResult('start', 'recorded', ref);
1000
+ });
1001
+ }
1002
+ export function startExternalWait(options, clock = systemClock) {
1003
+ const common = prepareCommon(options);
1004
+ const subject = subjectRef(common.hmacKey, assertRawLabel(options.subject));
1005
+ const flow = flowRef(common.hmacKey, options.subject, assertRawLabel(options.flow));
1006
+ const wait = waitRef(common.hmacKey, options.subject, options.flow, assertRawLabel(options.wait));
1007
+ const code = assertRawLabel(options.code, 32);
1008
+ if (!WAIT_CODE_PATTERN.test(code))
1009
+ fail('invalid_input');
1010
+ const ref = eventRef(common.hmacKey, 'external_wait_started', [subject, flow, wait, code]);
1011
+ return withStoreLock(common.storeRoot, false, () => {
1012
+ const { manifest, events, projection } = loadLockedStore(common);
1013
+ if (eventExists(events, ref))
1014
+ return eventResult('wait-start', 'unchanged', ref);
1015
+ if (!manifest.measurement_policy.predeclared_external_wait_codes.includes(code))
1016
+ fail('invalid_input');
1017
+ const active = activeSubjectFlow(projection, subject);
1018
+ if (!active || active.flowRef !== flow)
1019
+ fail('invalid_transition');
1020
+ if (active.waits.has(wait))
1021
+ fail('invalid_transition');
1022
+ if ([...active.waits.values()].some(existing => existing.completedAt === undefined))
1023
+ fail('invalid_transition');
1024
+ const occurredAt = assertIsoDate(clock.now());
1025
+ if (parseIsoMs(occurredAt) < parseIsoMs(active.startedAt))
1026
+ fail('invalid_transition');
1027
+ const event = {
1028
+ schema_version: MEMORY_LIFECYCLE_EVENT_SCHEMA,
1029
+ event_ref: ref,
1030
+ kind: 'external_wait_started',
1031
+ occurred_at: occurredAt,
1032
+ consent_ref: common.consentRef,
1033
+ subject_ref: subject,
1034
+ flow_ref: flow,
1035
+ wait_ref: wait,
1036
+ code,
1037
+ };
1038
+ appendEvent(common.storeRoot, events, event);
1039
+ return eventResult('wait-start', 'recorded', ref);
1040
+ });
1041
+ }
1042
+ export function endExternalWait(options, clock = systemClock) {
1043
+ const common = prepareCommon(options);
1044
+ const subject = subjectRef(common.hmacKey, assertRawLabel(options.subject));
1045
+ const flow = flowRef(common.hmacKey, options.subject, assertRawLabel(options.flow));
1046
+ const wait = waitRef(common.hmacKey, options.subject, options.flow, assertRawLabel(options.wait));
1047
+ const ref = eventRef(common.hmacKey, 'external_wait_ended', [subject, flow, wait]);
1048
+ return withStoreLock(common.storeRoot, false, () => {
1049
+ const { events, projection } = loadLockedStore(common);
1050
+ if (eventExists(events, ref))
1051
+ return eventResult('wait-end', 'unchanged', ref);
1052
+ const active = activeSubjectFlow(projection, subject);
1053
+ const interval = active?.waits.get(wait);
1054
+ if (!active || active.flowRef !== flow || !interval || interval.completedAt !== undefined)
1055
+ fail('invalid_transition');
1056
+ const occurredAt = assertIsoDate(clock.now());
1057
+ if (parseIsoMs(occurredAt) <= parseIsoMs(interval.startedAt))
1058
+ fail('invalid_transition');
1059
+ const event = {
1060
+ schema_version: MEMORY_LIFECYCLE_EVENT_SCHEMA,
1061
+ event_ref: ref,
1062
+ kind: 'external_wait_ended',
1063
+ occurred_at: occurredAt,
1064
+ consent_ref: common.consentRef,
1065
+ subject_ref: subject,
1066
+ flow_ref: flow,
1067
+ wait_ref: wait,
1068
+ };
1069
+ appendEvent(common.storeRoot, events, event);
1070
+ return eventResult('wait-end', 'recorded', ref);
1071
+ });
1072
+ }
1073
+ export function completeMemoryLifecycleFlow(options, clock = systemClock) {
1074
+ const common = prepareCommon(options);
1075
+ const subject = subjectRef(common.hmacKey, assertRawLabel(options.subject));
1076
+ const flow = flowRef(common.hmacKey, options.subject, assertRawLabel(options.flow));
1077
+ const ref = eventRef(common.hmacKey, 'flow_completed', [subject, flow]);
1078
+ return withStoreLock(common.storeRoot, false, () => {
1079
+ const { events, projection } = loadLockedStore(common);
1080
+ if (eventExists(events, ref))
1081
+ return eventResult('complete', 'unchanged', ref);
1082
+ const active = activeSubjectFlow(projection, subject);
1083
+ if (!active || active.flowRef !== flow)
1084
+ fail('invalid_transition');
1085
+ if ([...active.waits.values()].some(wait => wait.completedAt === undefined))
1086
+ fail('invalid_transition');
1087
+ const occurredAt = assertIsoDate(clock.now());
1088
+ if (parseIsoMs(occurredAt) <= parseIsoMs(active.startedAt))
1089
+ fail('invalid_transition');
1090
+ const event = {
1091
+ schema_version: MEMORY_LIFECYCLE_EVENT_SCHEMA,
1092
+ event_ref: ref,
1093
+ kind: 'flow_completed',
1094
+ occurred_at: occurredAt,
1095
+ consent_ref: common.consentRef,
1096
+ subject_ref: subject,
1097
+ flow_ref: flow,
1098
+ status: 'completed',
1099
+ };
1100
+ appendEvent(common.storeRoot, events, event);
1101
+ return eventResult('complete', 'recorded', ref);
1102
+ });
1103
+ }
1104
+ export function recordExperienceReflux(options, clock = systemClock) {
1105
+ const common = prepareCommon(options);
1106
+ const kind = assertRefluxKind(options.kind);
1107
+ const experience = experienceRef(common.hmacKey, assertRawLabel(options.experience));
1108
+ const evidence = evidenceRef(common.hmacKey, assertRawLabel(options.evidence, 2048));
1109
+ const ref = eventRef(common.hmacKey, 'experience_reflux_recorded', [kind, experience, evidence]);
1110
+ return withStoreLock(common.storeRoot, false, () => {
1111
+ const { events, projection } = loadLockedStore(common);
1112
+ if (eventExists(events, ref))
1113
+ return eventResult('record-reflux', 'unchanged', ref);
1114
+ if (projection.refluxEvents.some(event => event.experienceRef === experience && event.refluxKind === kind))
1115
+ fail('invalid_transition');
1116
+ if (kind === 'verified_outcome' && !projection.refluxEvents.some(event => event.experienceRef === experience && event.refluxKind === 'recalled')) {
1117
+ fail('invalid_transition');
1118
+ }
1119
+ const event = {
1120
+ schema_version: MEMORY_LIFECYCLE_EVENT_SCHEMA,
1121
+ event_ref: ref,
1122
+ kind: 'experience_reflux_recorded',
1123
+ occurred_at: assertIsoDate(clock.now()),
1124
+ consent_ref: common.consentRef,
1125
+ reflux_kind: kind,
1126
+ experience_ref: experience,
1127
+ evidence_ref: evidence,
1128
+ };
1129
+ appendEvent(common.storeRoot, events, event);
1130
+ return eventResult('record-reflux', 'recorded', ref);
1131
+ });
1132
+ }
1133
+ export function recordPreferenceAssertion(options, clock = systemClock) {
1134
+ const common = prepareCommon(options);
1135
+ const consumer = assertPreferenceConsumer(options.consumer);
1136
+ const assertion = assertionRef(common.hmacKey, assertRawLabel(options.assertion));
1137
+ const evidence = evidenceRef(common.hmacKey, assertRawLabel(options.evidence, 2048));
1138
+ const ref = eventRef(common.hmacKey, 'preference_recorded', [assertion, evidence, consumer]);
1139
+ return withStoreLock(common.storeRoot, false, () => {
1140
+ const { events, projection } = loadLockedStore(common);
1141
+ if (eventExists(events, ref))
1142
+ return eventResult('record-preference', 'unchanged', ref);
1143
+ if (projection.preferences.some(preference => preference.assertionRef === assertion))
1144
+ fail('invalid_transition');
1145
+ const event = {
1146
+ schema_version: MEMORY_LIFECYCLE_EVENT_SCHEMA,
1147
+ event_ref: ref,
1148
+ kind: 'preference_recorded',
1149
+ occurred_at: assertIsoDate(clock.now()),
1150
+ consent_ref: common.consentRef,
1151
+ assertion_ref: assertion,
1152
+ evidence_ref: evidence,
1153
+ consumer,
1154
+ hard_filter: false,
1155
+ };
1156
+ appendEvent(common.storeRoot, events, event);
1157
+ return eventResult('record-preference', 'recorded', ref);
1158
+ });
1159
+ }
1160
+ function eventResult(command, status, ref) {
1161
+ return { schema: 'memory_lifecycle_cli_result.v1', ok: true, command, status, event_ref: ref };
1162
+ }
1163
+ export function buildMemoryValueFixture(manifest, events, hmacKey) {
1164
+ assertDatasetKeyMatches(manifest, hmacKey);
1165
+ assertEventsBelongToDataset(manifest, events);
1166
+ const projection = projectLifecycleEvents(events);
1167
+ const pairs = [];
1168
+ for (const [subject, flows] of [...projection.flowsBySubject.entries()].sort(([a], [b]) => a.localeCompare(b))) {
1169
+ const completed = flows.filter(flow => flow.completedAt !== undefined).sort(compareFlows);
1170
+ if (completed.length < 2)
1171
+ continue;
1172
+ const first = completed[0];
1173
+ const returning = completed[1];
1174
+ if (parseIsoMs(returning.startedAt) <= parseIsoMs(first.completedAt))
1175
+ fail('invalid_store');
1176
+ const pairId = pseudonymousRef(hmacKey, 'pair', [subject, first.flowRef, returning.flowRef]);
1177
+ pairs.push({
1178
+ pair_id: pairId,
1179
+ subject_ref: subject,
1180
+ first: flowToMemoryValue(first, 1),
1181
+ returning: flowToMemoryValue(returning, 2),
1182
+ });
1183
+ }
1184
+ const base = {
1185
+ schema: MEMORY_VALUE_FIXTURE_SCHEMA,
1186
+ evidence_kind: manifest.source_kind,
1187
+ measurement_policy: manifest.measurement_policy,
1188
+ pairs,
1189
+ experience_reflux_events: projection.refluxEvents
1190
+ .slice()
1191
+ .sort((a, b) => a.experienceRef.localeCompare(b.experienceRef) || a.refluxKind.localeCompare(b.refluxKind))
1192
+ .map(event => ({ experience_id: event.experienceRef, kind: event.refluxKind, evidence_ref: event.evidenceRef })),
1193
+ preference_assertions: projection.preferences
1194
+ .slice()
1195
+ .sort((a, b) => a.assertionRef.localeCompare(b.assertionRef))
1196
+ .map(preference => ({
1197
+ assertion_id: preference.assertionRef,
1198
+ evidence_ref: preference.evidenceRef,
1199
+ consumer: preference.consumer,
1200
+ hard_filter: false,
1201
+ })),
1202
+ p4: manifest.p4,
1203
+ };
1204
+ const summaryDigest = memoryValueSummaryDigest(base);
1205
+ return {
1206
+ schema: base.schema,
1207
+ evidence_kind: base.evidence_kind,
1208
+ source_review: sourceReviewFor(manifest.source_kind, summaryDigest),
1209
+ measurement_policy: base.measurement_policy,
1210
+ pairs: base.pairs,
1211
+ experience_reflux_events: base.experience_reflux_events,
1212
+ preference_assertions: base.preference_assertions,
1213
+ p4: base.p4,
1214
+ };
1215
+ }
1216
+ function flowToMemoryValue(flow, eligiblePlanningIndex) {
1217
+ if (!flow.completedAt)
1218
+ fail('invalid_store');
1219
+ const waits = [...flow.waits.values()]
1220
+ .sort((a, b) => parseIsoMs(a.startedAt) - parseIsoMs(b.startedAt) || a.waitRef.localeCompare(b.waitRef))
1221
+ .map(wait => {
1222
+ if (!wait.completedAt)
1223
+ fail('invalid_store');
1224
+ return { code: wait.code, started_at: wait.startedAt, completed_at: wait.completedAt };
1225
+ });
1226
+ for (let index = 1; index < waits.length; index += 1) {
1227
+ if (parseIsoMs(waits[index].started_at) < parseIsoMs(waits[index - 1].completed_at))
1228
+ fail('invalid_store');
1229
+ }
1230
+ return {
1231
+ flow_id: flow.flowRef,
1232
+ eligible_planning_index: eligiblePlanningIndex,
1233
+ eligible: true,
1234
+ status: 'completed',
1235
+ started_at: flow.startedAt,
1236
+ completed_at: flow.completedAt,
1237
+ external_waits: waits,
1238
+ };
1239
+ }
1240
+ function sourceReviewFor(sourceKind, summaryDigest) {
1241
+ if (!SHA256_PATTERN.test(summaryDigest))
1242
+ fail('internal_error');
1243
+ if (sourceKind === 'synthetic_fixture') {
1244
+ return {
1245
+ schema_version: MEMORY_VALUE_SOURCE_REVIEW_SCHEMA,
1246
+ state: 'not_required_for_synthetic',
1247
+ reviewed_at: null,
1248
+ reviewer_ref: null,
1249
+ attestation_ref: null,
1250
+ private_source_digest_sha256: null,
1251
+ reviewed_summary_digest_sha256: null,
1252
+ checks: {
1253
+ raw_private_material_excluded: false,
1254
+ paired_cohort_source_reviewed: false,
1255
+ summary_matches_private_source: false,
1256
+ no_synthetic_or_test_subjects: false,
1257
+ },
1258
+ };
1259
+ }
1260
+ return {
1261
+ schema_version: MEMORY_VALUE_SOURCE_REVIEW_SCHEMA,
1262
+ state: 'candidate',
1263
+ reviewed_at: null,
1264
+ reviewer_ref: null,
1265
+ attestation_ref: null,
1266
+ private_source_digest_sha256: null,
1267
+ reviewed_summary_digest_sha256: summaryDigest,
1268
+ checks: {
1269
+ raw_private_material_excluded: true,
1270
+ paired_cohort_source_reviewed: false,
1271
+ summary_matches_private_source: false,
1272
+ no_synthetic_or_test_subjects: false,
1273
+ },
1274
+ };
1275
+ }
1276
+ export function exportMemoryLifecycleFixture(options) {
1277
+ const common = prepareCommon(options);
1278
+ return withStoreLock(common.storeRoot, false, () => {
1279
+ const { manifest, events } = loadLockedStore(common);
1280
+ const fixture = buildMemoryValueFixture(manifest, events, common.hmacKey);
1281
+ if (options.out) {
1282
+ const outputPath = resolve(options.out);
1283
+ writePrivateFileNoOverwrite(outputPath, `${JSON.stringify(fixture, null, 2)}\n`);
1284
+ }
1285
+ return {
1286
+ fixture,
1287
+ result: {
1288
+ schema: 'memory_lifecycle_cli_result.v1',
1289
+ ok: true,
1290
+ command: 'export',
1291
+ status: 'recorded',
1292
+ dataset_ref: manifest.dataset_ref,
1293
+ source_kind: manifest.source_kind,
1294
+ pair_count: fixture.pairs.length,
1295
+ output_written: Boolean(options.out),
1296
+ },
1297
+ };
1298
+ });
1299
+ }
1300
+ export function readStoreForTests(stateRoot) {
1301
+ const safeRoot = assertSafeStateRoot(stateRoot);
1302
+ const storeRoot = join(safeRoot, 'gotry-state', 'memory-lifecycle');
1303
+ return { manifest: readManifest(storeRoot), events: readEvents(storeRoot) };
1304
+ }
1305
+ export function storeRootForStateRoot(stateRoot) {
1306
+ return join(assertSafeStateRoot(stateRoot), 'gotry-state', 'memory-lifecycle');
1307
+ }
1308
+ export function fileMode(path) {
1309
+ return statSync(path).mode & 0o777;
1310
+ }