@senpi/runtime 3.0.6-dev.skill-manager-v2.20260629194505 → 3.0.9-dev.runtime-phase-2.20260707070820

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 (458) hide show
  1. package/dist/actions/action-events.d.ts +67 -0
  2. package/dist/actions/action-events.d.ts.map +1 -0
  3. package/dist/actions/action-events.js +164 -0
  4. package/dist/actions/action-events.js.map +1 -0
  5. package/dist/actions/close-position/close-position.action.d.ts +1 -1
  6. package/dist/actions/close-position/close-position.action.d.ts.map +1 -1
  7. package/dist/actions/close-position/close-position.action.js +108 -86
  8. package/dist/actions/close-position/close-position.action.js.map +1 -1
  9. package/dist/actions/decision-engine.d.ts.map +1 -1
  10. package/dist/actions/decision-engine.js +40 -28
  11. package/dist/actions/decision-engine.js.map +1 -1
  12. package/dist/actions/event-derivation.d.ts +61 -0
  13. package/dist/actions/event-derivation.d.ts.map +1 -0
  14. package/dist/actions/event-derivation.js +180 -0
  15. package/dist/actions/event-derivation.js.map +1 -0
  16. package/dist/actions/llm-decision/anthropic-llm-decision.d.ts +5 -9
  17. package/dist/actions/llm-decision/anthropic-llm-decision.d.ts.map +1 -1
  18. package/dist/actions/llm-decision/anthropic-llm-decision.js +6 -87
  19. package/dist/actions/llm-decision/anthropic-llm-decision.js.map +1 -1
  20. package/dist/actions/llm-decision/factory.d.ts +0 -6
  21. package/dist/actions/llm-decision/factory.d.ts.map +1 -1
  22. package/dist/actions/llm-decision/factory.js +0 -2
  23. package/dist/actions/llm-decision/factory.js.map +1 -1
  24. package/dist/actions/llm-decision/openclaw-llm-decision.d.ts.map +1 -1
  25. package/dist/actions/llm-decision/openclaw-llm-decision.js +26 -7
  26. package/dist/actions/llm-decision/openclaw-llm-decision.js.map +1 -1
  27. package/dist/actions/open-position/open-position.action.d.ts +1 -1
  28. package/dist/actions/open-position/open-position.action.d.ts.map +1 -1
  29. package/dist/actions/open-position/open-position.action.js +282 -224
  30. package/dist/actions/open-position/open-position.action.js.map +1 -1
  31. package/dist/actions/position-tracker/position-tracker.action.d.ts.map +1 -1
  32. package/dist/actions/position-tracker/position-tracker.action.js +3 -6
  33. package/dist/actions/position-tracker/position-tracker.action.js.map +1 -1
  34. package/dist/cli/guide-commands.d.ts.map +1 -1
  35. package/dist/cli/guide-commands.js +61 -0
  36. package/dist/cli/guide-commands.js.map +1 -1
  37. package/dist/cli/senpi-commands.d.ts +14 -0
  38. package/dist/cli/senpi-commands.d.ts.map +1 -1
  39. package/dist/cli/senpi-commands.js +390 -2
  40. package/dist/cli/senpi-commands.js.map +1 -1
  41. package/dist/dsl/engine-client/event-mapping.d.ts.map +1 -1
  42. package/dist/dsl/engine-client/event-mapping.js +0 -3
  43. package/dist/dsl/engine-client/event-mapping.js.map +1 -1
  44. package/dist/dsl/events/build-closed-event.d.ts.map +1 -1
  45. package/dist/dsl/events/build-closed-event.js +0 -1
  46. package/dist/dsl/events/build-closed-event.js.map +1 -1
  47. package/dist/dsl/events/handlers.d.ts.map +1 -1
  48. package/dist/dsl/events/handlers.js +2 -4
  49. package/dist/dsl/events/handlers.js.map +1 -1
  50. package/dist/dsl/events/initial-state.d.ts.map +1 -1
  51. package/dist/dsl/events/initial-state.js +1 -0
  52. package/dist/dsl/events/initial-state.js.map +1 -1
  53. package/dist/dsl/monitor/create-monitor.d.ts +3 -0
  54. package/dist/dsl/monitor/create-monitor.d.ts.map +1 -1
  55. package/dist/dsl/monitor/create-monitor.js +76 -58
  56. package/dist/dsl/monitor/create-monitor.js.map +1 -1
  57. package/dist/dsl/monitor/dsl-failure-events.d.ts +42 -0
  58. package/dist/dsl/monitor/dsl-failure-events.d.ts.map +1 -0
  59. package/dist/dsl/monitor/dsl-failure-events.js +73 -0
  60. package/dist/dsl/monitor/dsl-failure-events.js.map +1 -0
  61. package/dist/dsl/monitor/process-one-position.d.ts +2 -1
  62. package/dist/dsl/monitor/process-one-position.d.ts.map +1 -1
  63. package/dist/dsl/monitor/process-one-position.js +130 -196
  64. package/dist/dsl/monitor/process-one-position.js.map +1 -1
  65. package/dist/dsl/plugin/index.d.ts +10 -0
  66. package/dist/dsl/plugin/index.d.ts.map +1 -1
  67. package/dist/dsl/plugin/index.js +48 -4
  68. package/dist/dsl/plugin/index.js.map +1 -1
  69. package/dist/dsl/plugin/options.d.ts +3 -0
  70. package/dist/dsl/plugin/options.d.ts.map +1 -1
  71. package/dist/health/types.d.ts +14 -0
  72. package/dist/health/types.d.ts.map +1 -1
  73. package/dist/health/types.js.map +1 -1
  74. package/dist/index.d.ts +1 -0
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +255 -77
  77. package/dist/index.js.map +1 -1
  78. package/dist/risk/risk-audit-log.d.ts +7 -0
  79. package/dist/risk/risk-audit-log.d.ts.map +1 -1
  80. package/dist/risk/risk-audit-log.js +48 -1
  81. package/dist/risk/risk-audit-log.js.map +1 -1
  82. package/dist/runtime/__tests__/helpers/runtime-gateway-harness.d.ts +2 -0
  83. package/dist/runtime/__tests__/helpers/runtime-gateway-harness.d.ts.map +1 -1
  84. package/dist/runtime/__tests__/helpers/runtime-gateway-harness.js +24 -3
  85. package/dist/runtime/__tests__/helpers/runtime-gateway-harness.js.map +1 -1
  86. package/dist/runtime/auto-update/coordinator.js +2 -2
  87. package/dist/runtime/auto-update/coordinator.js.map +1 -1
  88. package/dist/runtime/create-actions.d.ts.map +1 -1
  89. package/dist/runtime/create-actions.js +40 -15
  90. package/dist/runtime/create-actions.js.map +1 -1
  91. package/dist/runtime/create-runtime-context.d.ts +1 -1
  92. package/dist/runtime/create-runtime-context.d.ts.map +1 -1
  93. package/dist/runtime/create-scanner-module.d.ts +2 -1
  94. package/dist/runtime/create-scanner-module.d.ts.map +1 -1
  95. package/dist/runtime/create-scanner-module.js +2 -1
  96. package/dist/runtime/create-scanner-module.js.map +1 -1
  97. package/dist/runtime/domain-events.d.ts +43 -0
  98. package/dist/runtime/domain-events.d.ts.map +1 -0
  99. package/dist/runtime/domain-events.js +181 -0
  100. package/dist/runtime/domain-events.js.map +1 -0
  101. package/dist/runtime/lifecycle-events.d.ts +86 -0
  102. package/dist/runtime/lifecycle-events.d.ts.map +1 -0
  103. package/dist/runtime/lifecycle-events.js +200 -0
  104. package/dist/runtime/lifecycle-events.js.map +1 -0
  105. package/dist/runtime/notifications.js +2 -2
  106. package/dist/runtime/notifications.js.map +1 -1
  107. package/dist/{tracking → runtime}/position-id-registry.d.ts +14 -1
  108. package/dist/runtime/position-id-registry.d.ts.map +1 -0
  109. package/dist/{tracking → runtime}/position-id-registry.js +20 -3
  110. package/dist/runtime/position-id-registry.js.map +1 -0
  111. package/dist/runtime/run.d.ts +2 -4
  112. package/dist/runtime/run.d.ts.map +1 -1
  113. package/dist/runtime/run.js.map +1 -1
  114. package/dist/runtime/runtime-schema.d.ts +276 -588
  115. package/dist/runtime/runtime-schema.d.ts.map +1 -1
  116. package/dist/runtime/runtime-schema.js +8 -28
  117. package/dist/runtime/runtime-schema.js.map +1 -1
  118. package/dist/runtime/runtime.d.ts +23 -9
  119. package/dist/runtime/runtime.d.ts.map +1 -1
  120. package/dist/runtime/runtime.js +276 -248
  121. package/dist/runtime/runtime.js.map +1 -1
  122. package/dist/runtime/strategy-lifecycle.d.ts.map +1 -1
  123. package/dist/runtime/strategy-lifecycle.js +13 -1
  124. package/dist/runtime/strategy-lifecycle.js.map +1 -1
  125. package/dist/runtime/supervisor/long-running-supervisor.d.ts +3 -0
  126. package/dist/runtime/supervisor/long-running-supervisor.d.ts.map +1 -1
  127. package/dist/runtime/supervisor/long-running-supervisor.js +27 -53
  128. package/dist/runtime/supervisor/long-running-supervisor.js.map +1 -1
  129. package/dist/runtime-api/intake/intake-events.d.ts +44 -0
  130. package/dist/runtime-api/intake/intake-events.d.ts.map +1 -0
  131. package/dist/runtime-api/intake/intake-events.js +131 -0
  132. package/dist/runtime-api/intake/intake-events.js.map +1 -0
  133. package/dist/runtime-api/intake/scanner-launcher.d.ts +2 -0
  134. package/dist/runtime-api/intake/scanner-launcher.d.ts.map +1 -1
  135. package/dist/runtime-api/intake/scanner-launcher.js +58 -15
  136. package/dist/runtime-api/intake/scanner-launcher.js.map +1 -1
  137. package/dist/runtime-api/intake/scanner-registry.d.ts +3 -0
  138. package/dist/runtime-api/intake/scanner-registry.d.ts.map +1 -1
  139. package/dist/runtime-api/intake/scanner-registry.js +3 -0
  140. package/dist/runtime-api/intake/scanner-registry.js.map +1 -1
  141. package/dist/runtime-api/intake/supervisor-events.d.ts +61 -0
  142. package/dist/runtime-api/intake/supervisor-events.d.ts.map +1 -0
  143. package/dist/runtime-api/intake/supervisor-events.js +173 -0
  144. package/dist/runtime-api/intake/supervisor-events.js.map +1 -0
  145. package/dist/runtime-api/routes/signals.d.ts +1 -1
  146. package/dist/runtime-api/routes/signals.d.ts.map +1 -1
  147. package/dist/runtime-api/routes/signals.js +121 -35
  148. package/dist/runtime-api/routes/signals.js.map +1 -1
  149. package/dist/runtime-api/server.d.ts.map +1 -1
  150. package/dist/runtime-api/server.js +10 -1
  151. package/dist/runtime-api/server.js.map +1 -1
  152. package/dist/scanners/engine/data-providers.d.ts +3 -0
  153. package/dist/scanners/engine/data-providers.d.ts.map +1 -1
  154. package/dist/scanners/engine/data-providers.js.map +1 -1
  155. package/dist/scanners/engine/engine.d.ts +18 -0
  156. package/dist/scanners/engine/engine.d.ts.map +1 -1
  157. package/dist/scanners/engine/engine.js +96 -2
  158. package/dist/scanners/engine/engine.js.map +1 -1
  159. package/dist/scanners/engine/input-resolver.d.ts.map +1 -1
  160. package/dist/scanners/engine/input-resolver.js +9 -7
  161. package/dist/scanners/engine/input-resolver.js.map +1 -1
  162. package/dist/scanners/runtime-module.d.ts +3 -0
  163. package/dist/scanners/runtime-module.d.ts.map +1 -1
  164. package/dist/scanners/runtime-module.js +7 -0
  165. package/dist/scanners/runtime-module.js.map +1 -1
  166. package/dist/senpi/client.d.ts +10 -0
  167. package/dist/senpi/client.d.ts.map +1 -1
  168. package/dist/senpi/client.js +113 -46
  169. package/dist/senpi/client.js.map +1 -1
  170. package/dist/skills-manager/bootstrap.d.ts.map +1 -1
  171. package/dist/skills-manager/bootstrap.js +22 -33
  172. package/dist/skills-manager/bootstrap.js.map +1 -1
  173. package/dist/skills-manager/clone-groups.d.ts +20 -0
  174. package/dist/skills-manager/clone-groups.d.ts.map +1 -0
  175. package/dist/skills-manager/clone-groups.js +45 -0
  176. package/dist/skills-manager/clone-groups.js.map +1 -0
  177. package/dist/skills-manager/coordinator.d.ts.map +1 -1
  178. package/dist/skills-manager/coordinator.js +111 -75
  179. package/dist/skills-manager/coordinator.js.map +1 -1
  180. package/dist/skills-manager/manifest.d.ts +24 -0
  181. package/dist/skills-manager/manifest.d.ts.map +1 -1
  182. package/dist/skills-manager/manifest.js +23 -10
  183. package/dist/skills-manager/manifest.js.map +1 -1
  184. package/dist/skills-manager/skills-manifest.json +12 -7
  185. package/dist/skills-manager/types.d.ts +12 -0
  186. package/dist/skills-manager/types.d.ts.map +1 -1
  187. package/dist/state/state-events.d.ts +13 -0
  188. package/dist/state/state-events.d.ts.map +1 -0
  189. package/dist/state/state-events.js +22 -0
  190. package/dist/state/state-events.js.map +1 -0
  191. package/dist/state/state-manager.d.ts.map +1 -1
  192. package/dist/state/state-manager.js +14 -1
  193. package/dist/state/state-manager.js.map +1 -1
  194. package/dist/telemetry/attributes.d.ts +13 -0
  195. package/dist/telemetry/attributes.d.ts.map +1 -0
  196. package/dist/telemetry/attributes.js +22 -0
  197. package/dist/telemetry/attributes.js.map +1 -0
  198. package/dist/{tracking → telemetry}/context.d.ts +12 -5
  199. package/dist/telemetry/context.d.ts.map +1 -0
  200. package/dist/{tracking → telemetry}/context.js +4 -4
  201. package/dist/telemetry/context.js.map +1 -0
  202. package/dist/{recording/records.d.ts → telemetry/event-builders.d.ts} +145 -33
  203. package/dist/telemetry/event-builders.d.ts.map +1 -0
  204. package/dist/{recording/wiring/record-builders.js → telemetry/event-builders.js} +94 -40
  205. package/dist/telemetry/event-builders.js.map +1 -0
  206. package/dist/telemetry/event-store.d.ts +66 -0
  207. package/dist/telemetry/event-store.d.ts.map +1 -0
  208. package/dist/telemetry/event-store.js +202 -0
  209. package/dist/telemetry/event-store.js.map +1 -0
  210. package/dist/telemetry/identity.d.ts +72 -0
  211. package/dist/telemetry/identity.d.ts.map +1 -0
  212. package/dist/{recording/wiring → telemetry}/identity.js +6 -2
  213. package/dist/telemetry/identity.js.map +1 -0
  214. package/dist/telemetry/metrics.d.ts +169 -0
  215. package/dist/telemetry/metrics.d.ts.map +1 -0
  216. package/dist/telemetry/metrics.js +437 -0
  217. package/dist/telemetry/metrics.js.map +1 -0
  218. package/dist/telemetry/otel-sdk.d.ts +93 -0
  219. package/dist/telemetry/otel-sdk.d.ts.map +1 -0
  220. package/dist/telemetry/otel-sdk.js +297 -0
  221. package/dist/telemetry/otel-sdk.js.map +1 -0
  222. package/dist/telemetry/spans/constants.d.ts +12 -0
  223. package/dist/telemetry/spans/constants.d.ts.map +1 -0
  224. package/dist/telemetry/spans/constants.js +12 -0
  225. package/dist/telemetry/spans/constants.js.map +1 -0
  226. package/dist/telemetry/spans/gen-ai.d.ts +74 -0
  227. package/dist/telemetry/spans/gen-ai.d.ts.map +1 -0
  228. package/dist/telemetry/spans/gen-ai.js +339 -0
  229. package/dist/telemetry/spans/gen-ai.js.map +1 -0
  230. package/dist/telemetry/spans/index.d.ts +11 -0
  231. package/dist/telemetry/spans/index.d.ts.map +1 -0
  232. package/dist/telemetry/spans/index.js +11 -0
  233. package/dist/telemetry/spans/index.js.map +1 -0
  234. package/dist/{tracking → telemetry}/spans/redact-pii.d.ts +19 -21
  235. package/dist/telemetry/spans/redact-pii.d.ts.map +1 -0
  236. package/dist/{tracking → telemetry}/spans/redact-pii.js +35 -32
  237. package/dist/telemetry/spans/redact-pii.js.map +1 -0
  238. package/dist/telemetry/spans/sanitize-payload.d.ts.map +1 -0
  239. package/dist/telemetry/spans/sanitize-payload.js.map +1 -0
  240. package/dist/telemetry/spans/span-hooks.d.ts +18 -0
  241. package/dist/telemetry/spans/span-hooks.d.ts.map +1 -0
  242. package/dist/telemetry/spans/span-hooks.js +764 -0
  243. package/dist/telemetry/spans/span-hooks.js.map +1 -0
  244. package/dist/telemetry/tool-plane.d.ts +31 -0
  245. package/dist/telemetry/tool-plane.d.ts.map +1 -0
  246. package/dist/telemetry/tool-plane.js +70 -0
  247. package/dist/telemetry/tool-plane.js.map +1 -0
  248. package/dist/telemetry/trace-identity.d.ts +32 -0
  249. package/dist/telemetry/trace-identity.d.ts.map +1 -0
  250. package/dist/telemetry/trace-identity.js +62 -0
  251. package/dist/telemetry/trace-identity.js.map +1 -0
  252. package/dist/telemetry/tracing.d.ts +33 -0
  253. package/dist/telemetry/tracing.d.ts.map +1 -0
  254. package/dist/telemetry/tracing.js +70 -0
  255. package/dist/telemetry/tracing.js.map +1 -0
  256. package/dist/types/dsl/index.d.ts +8 -9
  257. package/dist/types/dsl/index.d.ts.map +1 -1
  258. package/dist/types/runtime.d.ts +1 -1
  259. package/dist/types/runtime.d.ts.map +1 -1
  260. package/dist/types/scanner.d.ts +2 -0
  261. package/dist/types/scanner.d.ts.map +1 -1
  262. package/dist/utils/event-catalog.d.ts +506 -0
  263. package/dist/utils/event-catalog.d.ts.map +1 -0
  264. package/dist/utils/event-catalog.js +142 -0
  265. package/dist/utils/event-catalog.js.map +1 -0
  266. package/dist/utils/logger.d.ts +63 -5
  267. package/dist/utils/logger.d.ts.map +1 -1
  268. package/dist/utils/logger.js +360 -27
  269. package/dist/utils/logger.js.map +1 -1
  270. package/dist/utils/wallet-address.d.ts +3 -0
  271. package/dist/utils/wallet-address.d.ts.map +1 -0
  272. package/dist/utils/wallet-address.js +17 -0
  273. package/dist/utils/wallet-address.js.map +1 -0
  274. package/openclaw.plugin.json +20 -6
  275. package/package.json +10 -2
  276. package/dist/actions/tracking-helpers.d.ts +0 -28
  277. package/dist/actions/tracking-helpers.d.ts.map +0 -1
  278. package/dist/actions/tracking-helpers.js +0 -93
  279. package/dist/actions/tracking-helpers.js.map +0 -1
  280. package/dist/recording/emitter.d.ts +0 -27
  281. package/dist/recording/emitter.d.ts.map +0 -1
  282. package/dist/recording/emitter.js +0 -2
  283. package/dist/recording/emitter.js.map +0 -1
  284. package/dist/recording/identity.d.ts +0 -34
  285. package/dist/recording/identity.d.ts.map +0 -1
  286. package/dist/recording/identity.js +0 -2
  287. package/dist/recording/identity.js.map +0 -1
  288. package/dist/recording/index.d.ts +0 -11
  289. package/dist/recording/index.d.ts.map +0 -1
  290. package/dist/recording/index.js +0 -2
  291. package/dist/recording/index.js.map +0 -1
  292. package/dist/recording/noop-emitter.d.ts +0 -23
  293. package/dist/recording/noop-emitter.d.ts.map +0 -1
  294. package/dist/recording/noop-emitter.js +0 -22
  295. package/dist/recording/noop-emitter.js.map +0 -1
  296. package/dist/recording/otel/attributes.d.ts +0 -35
  297. package/dist/recording/otel/attributes.d.ts.map +0 -1
  298. package/dist/recording/otel/attributes.js +0 -131
  299. package/dist/recording/otel/attributes.js.map +0 -1
  300. package/dist/recording/otel/constants.d.ts +0 -123
  301. package/dist/recording/otel/constants.d.ts.map +0 -1
  302. package/dist/recording/otel/constants.js +0 -172
  303. package/dist/recording/otel/constants.js.map +0 -1
  304. package/dist/recording/otel/ids.d.ts +0 -25
  305. package/dist/recording/otel/ids.d.ts.map +0 -1
  306. package/dist/recording/otel/ids.js +0 -37
  307. package/dist/recording/otel/ids.js.map +0 -1
  308. package/dist/recording/otel/index.d.ts +0 -13
  309. package/dist/recording/otel/index.d.ts.map +0 -1
  310. package/dist/recording/otel/index.js +0 -9
  311. package/dist/recording/otel/index.js.map +0 -1
  312. package/dist/recording/otel/mappers.d.ts +0 -100
  313. package/dist/recording/otel/mappers.d.ts.map +0 -1
  314. package/dist/recording/otel/mappers.js +0 -683
  315. package/dist/recording/otel/mappers.js.map +0 -1
  316. package/dist/recording/otel/otel-emitter.d.ts +0 -43
  317. package/dist/recording/otel/otel-emitter.d.ts.map +0 -1
  318. package/dist/recording/otel/otel-emitter.js +0 -99
  319. package/dist/recording/otel/otel-emitter.js.map +0 -1
  320. package/dist/recording/otel/redaction.d.ts +0 -47
  321. package/dist/recording/otel/redaction.d.ts.map +0 -1
  322. package/dist/recording/otel/redaction.js +0 -88
  323. package/dist/recording/otel/redaction.js.map +0 -1
  324. package/dist/recording/records.d.ts.map +0 -1
  325. package/dist/recording/records.js +0 -14
  326. package/dist/recording/records.js.map +0 -1
  327. package/dist/recording/transport/batcher.d.ts +0 -59
  328. package/dist/recording/transport/batcher.d.ts.map +0 -1
  329. package/dist/recording/transport/batcher.js +0 -234
  330. package/dist/recording/transport/batcher.js.map +0 -1
  331. package/dist/recording/transport/client.d.ts +0 -41
  332. package/dist/recording/transport/client.d.ts.map +0 -1
  333. package/dist/recording/transport/client.js +0 -69
  334. package/dist/recording/transport/client.js.map +0 -1
  335. package/dist/recording/transport/config.d.ts +0 -53
  336. package/dist/recording/transport/config.d.ts.map +0 -1
  337. package/dist/recording/transport/config.js +0 -41
  338. package/dist/recording/transport/config.js.map +0 -1
  339. package/dist/recording/transport/index.d.ts +0 -16
  340. package/dist/recording/transport/index.d.ts.map +0 -1
  341. package/dist/recording/transport/index.js +0 -12
  342. package/dist/recording/transport/index.js.map +0 -1
  343. package/dist/recording/transport/rows.d.ts +0 -88
  344. package/dist/recording/transport/rows.d.ts.map +0 -1
  345. package/dist/recording/transport/rows.js +0 -15
  346. package/dist/recording/transport/rows.js.map +0 -1
  347. package/dist/recording/wiring/emitter-factory.d.ts +0 -39
  348. package/dist/recording/wiring/emitter-factory.d.ts.map +0 -1
  349. package/dist/recording/wiring/emitter-factory.js +0 -62
  350. package/dist/recording/wiring/emitter-factory.js.map +0 -1
  351. package/dist/recording/wiring/identity.d.ts +0 -27
  352. package/dist/recording/wiring/identity.d.ts.map +0 -1
  353. package/dist/recording/wiring/identity.js.map +0 -1
  354. package/dist/recording/wiring/index.d.ts +0 -12
  355. package/dist/recording/wiring/index.d.ts.map +0 -1
  356. package/dist/recording/wiring/index.js +0 -9
  357. package/dist/recording/wiring/index.js.map +0 -1
  358. package/dist/recording/wiring/record-builders.d.ts +0 -107
  359. package/dist/recording/wiring/record-builders.d.ts.map +0 -1
  360. package/dist/recording/wiring/record-builders.js.map +0 -1
  361. package/dist/recording/wiring/subscriber.d.ts +0 -28
  362. package/dist/recording/wiring/subscriber.d.ts.map +0 -1
  363. package/dist/recording/wiring/subscriber.js +0 -173
  364. package/dist/recording/wiring/subscriber.js.map +0 -1
  365. package/dist/recording/wiring/values.d.ts +0 -19
  366. package/dist/recording/wiring/values.d.ts.map +0 -1
  367. package/dist/recording/wiring/values.js +0 -49
  368. package/dist/recording/wiring/values.js.map +0 -1
  369. package/dist/tracking/build-rehydrate-items.d.ts +0 -15
  370. package/dist/tracking/build-rehydrate-items.d.ts.map +0 -1
  371. package/dist/tracking/build-rehydrate-items.js +0 -19
  372. package/dist/tracking/build-rehydrate-items.js.map +0 -1
  373. package/dist/tracking/constants.d.ts +0 -24
  374. package/dist/tracking/constants.d.ts.map +0 -1
  375. package/dist/tracking/constants.js +0 -52
  376. package/dist/tracking/constants.js.map +0 -1
  377. package/dist/tracking/context.d.ts.map +0 -1
  378. package/dist/tracking/context.js.map +0 -1
  379. package/dist/tracking/index.d.ts +0 -16
  380. package/dist/tracking/index.d.ts.map +0 -1
  381. package/dist/tracking/index.js +0 -11
  382. package/dist/tracking/index.js.map +0 -1
  383. package/dist/tracking/plugin-event-tracker.d.ts +0 -13
  384. package/dist/tracking/plugin-event-tracker.d.ts.map +0 -1
  385. package/dist/tracking/plugin-event-tracker.js +0 -27
  386. package/dist/tracking/plugin-event-tracker.js.map +0 -1
  387. package/dist/tracking/position-id-registry.d.ts.map +0 -1
  388. package/dist/tracking/position-id-registry.js.map +0 -1
  389. package/dist/tracking/spans/constants.d.ts +0 -19
  390. package/dist/tracking/spans/constants.d.ts.map +0 -1
  391. package/dist/tracking/spans/constants.js +0 -31
  392. package/dist/tracking/spans/constants.js.map +0 -1
  393. package/dist/tracking/spans/fan-out-span-transport.d.ts +0 -22
  394. package/dist/tracking/spans/fan-out-span-transport.d.ts.map +0 -1
  395. package/dist/tracking/spans/fan-out-span-transport.js +0 -49
  396. package/dist/tracking/spans/fan-out-span-transport.js.map +0 -1
  397. package/dist/tracking/spans/index.d.ts +0 -13
  398. package/dist/tracking/spans/index.d.ts.map +0 -1
  399. package/dist/tracking/spans/index.js +0 -16
  400. package/dist/tracking/spans/index.js.map +0 -1
  401. package/dist/tracking/spans/otel/fit-row-budget.d.ts +0 -22
  402. package/dist/tracking/spans/otel/fit-row-budget.d.ts.map +0 -1
  403. package/dist/tracking/spans/otel/fit-row-budget.js +0 -91
  404. package/dist/tracking/spans/otel/fit-row-budget.js.map +0 -1
  405. package/dist/tracking/spans/otel/map-span-to-trace-row.d.ts +0 -16
  406. package/dist/tracking/spans/otel/map-span-to-trace-row.d.ts.map +0 -1
  407. package/dist/tracking/spans/otel/map-span-to-trace-row.js +0 -227
  408. package/dist/tracking/spans/otel/map-span-to-trace-row.js.map +0 -1
  409. package/dist/tracking/spans/otel/recording-span-transport.d.ts +0 -43
  410. package/dist/tracking/spans/otel/recording-span-transport.d.ts.map +0 -1
  411. package/dist/tracking/spans/otel/recording-span-transport.js +0 -67
  412. package/dist/tracking/spans/otel/recording-span-transport.js.map +0 -1
  413. package/dist/tracking/spans/otel/span-ids.d.ts +0 -22
  414. package/dist/tracking/spans/otel/span-ids.d.ts.map +0 -1
  415. package/dist/tracking/spans/otel/span-ids.js +0 -32
  416. package/dist/tracking/spans/otel/span-ids.js.map +0 -1
  417. package/dist/tracking/spans/plugin-span-tracker.d.ts +0 -9
  418. package/dist/tracking/spans/plugin-span-tracker.d.ts.map +0 -1
  419. package/dist/tracking/spans/plugin-span-tracker.js +0 -115
  420. package/dist/tracking/spans/plugin-span-tracker.js.map +0 -1
  421. package/dist/tracking/spans/redact-pii.d.ts.map +0 -1
  422. package/dist/tracking/spans/redact-pii.js.map +0 -1
  423. package/dist/tracking/spans/sanitize-payload.d.ts.map +0 -1
  424. package/dist/tracking/spans/sanitize-payload.js.map +0 -1
  425. package/dist/tracking/spans/span-hooks.d.ts +0 -28
  426. package/dist/tracking/spans/span-hooks.d.ts.map +0 -1
  427. package/dist/tracking/spans/span-hooks.js +0 -409
  428. package/dist/tracking/spans/span-hooks.js.map +0 -1
  429. package/dist/tracking/spans/span-tracker.d.ts +0 -133
  430. package/dist/tracking/spans/span-tracker.d.ts.map +0 -1
  431. package/dist/tracking/spans/span-tracker.js +0 -721
  432. package/dist/tracking/spans/span-tracker.js.map +0 -1
  433. package/dist/tracking/spans/span-transport.d.ts +0 -71
  434. package/dist/tracking/spans/span-transport.d.ts.map +0 -1
  435. package/dist/tracking/spans/span-transport.js +0 -240
  436. package/dist/tracking/spans/span-transport.js.map +0 -1
  437. package/dist/tracking/spans/types.d.ts +0 -101
  438. package/dist/tracking/spans/types.d.ts.map +0 -1
  439. package/dist/tracking/spans/types.js +0 -6
  440. package/dist/tracking/spans/types.js.map +0 -1
  441. package/dist/tracking/tracker.d.ts +0 -30
  442. package/dist/tracking/tracker.d.ts.map +0 -1
  443. package/dist/tracking/tracker.js +0 -66
  444. package/dist/tracking/tracker.js.map +0 -1
  445. package/dist/tracking/tracking-handler.d.ts +0 -12
  446. package/dist/tracking/tracking-handler.d.ts.map +0 -1
  447. package/dist/tracking/tracking-handler.js +0 -148
  448. package/dist/tracking/tracking-handler.js.map +0 -1
  449. package/dist/tracking/transport.d.ts +0 -35
  450. package/dist/tracking/transport.d.ts.map +0 -1
  451. package/dist/tracking/transport.js +0 -133
  452. package/dist/tracking/transport.js.map +0 -1
  453. package/dist/tracking/types.d.ts +0 -21
  454. package/dist/tracking/types.d.ts.map +0 -1
  455. package/dist/tracking/types.js +0 -6
  456. package/dist/tracking/types.js.map +0 -1
  457. /package/dist/{tracking → telemetry}/spans/sanitize-payload.d.ts +0 -0
  458. /package/dist/{tracking → telemetry}/spans/sanitize-payload.js +0 -0
@@ -5,12 +5,17 @@ import { dslTick, exchangeStopLossTriggerPx } from "../engine/index.js";
5
5
  import { CLOSE_REASON, MAX_CONSECUTIVE_CLOSE_FAILURES, DSL_EXTERNAL_RETRIES, DSL_EXTERNAL_RETRY_DELAY_MS, DSL_EVENTS, EVENTS, DSL_PRICE_FETCH_FAILURE_WARN_THRESHOLD, DSL_HEARTBEAT_FIRST_HOUR_MS, DSL_HEARTBEAT_INTERVAL_MS, DSL_HEARTBEAT_TIER_SUPPRESS_MS, } from "../../constants/dsl/index.js";
6
6
  import { logger } from "../../utils/logger/dsl.js";
7
7
  import { withRetry } from "../../utils/retry.js";
8
+ import { withSpan } from "../../telemetry/tracing.js";
9
+ import { errorTypeOf } from "../../telemetry/spans/gen-ai.js";
10
+ import { recordDslDegradation } from "../../telemetry/metrics.js";
8
11
  import { effectiveDex } from "./effective-dex.js";
9
12
  import { shouldSyncExchangeSl } from "./exchange-sync.js";
10
13
  import { mapTiersToEngineConfig, mapEnginePositionToStateFields, parseSlOrderId } from "../engine-client/config-mapping.js";
11
14
  import { mapBackendEventToBusEvent } from "../engine-client/event-mapping.js";
12
15
  import { buildDslClosedEventFromState } from "../events/build-closed-event.js";
13
16
  import { parseCloseFillDetail } from "../../senpi/client.js";
17
+ import { emitEvent } from "../../actions/event-derivation.js";
18
+ import { buildSlSyncFailedEvent, buildPriceFetchStaleEvent, buildHandoffFailedEvent, } from "./dsl-failure-events.js";
14
19
  /**
15
20
  * Re-read the key under its per-key lock; if it is still active, archive it and return true.
16
21
  * If a competing locked writer already archived/inactivated it, skip and return false (WARN).
@@ -60,11 +65,18 @@ async function setIfStillActive(stateManager, key, address, asset, buildNext, ct
60
65
  function closedEmitStamps(state, fill = {}) {
61
66
  return {
62
67
  __positionId: state.positionId ?? state.correlationId,
63
- __correlationId: state.correlationId,
64
68
  ...fill,
65
69
  };
66
70
  }
67
- export async function processOnePosition(ctx, key, state, price) {
71
+ /** The position identity a DSL failure event pins onto its record. */
72
+ function failureContext(state) {
73
+ return {
74
+ asset: state.asset,
75
+ dex: state.dex || undefined,
76
+ positionId: state.positionId ?? state.correlationId,
77
+ };
78
+ }
79
+ export async function processOnePosition(ctx, key, state, price, span) {
68
80
  const { tickId, ts, now: isoNow, stateManager, strategyStates, bus, isSlPlacementInProgress = () => false } = ctx;
69
81
  const strategy = strategyStates.get(state.address);
70
82
  if (!strategy) {
@@ -93,13 +105,15 @@ export async function processOnePosition(ctx, key, state, price) {
93
105
  });
94
106
  if (state.slOrderId != null) {
95
107
  try {
96
- const status = await withRetry(() => strategy.getOrderStatus(state.slOrderId), {
108
+ const status = await withSpan("dsl.sl_check", {}, () => withRetry(() => strategy.getOrderStatus(state.slOrderId), {
97
109
  retries: DSL_EXTERNAL_RETRIES,
98
110
  delayMs: DSL_EXTERNAL_RETRY_DELAY_MS,
99
111
  label: "getOrderStatus (SL-hit check)",
100
112
  onRetry: (attempt, remaining, err) => logger.warn("[dsl] getOrderStatus retry", { asset: state.asset, attempt, remaining, err }),
101
- });
113
+ }));
102
114
  if (status?.filled) {
115
+ span.addEvent("external_close_detected", { source: "sl_order" });
116
+ span.setAttribute("senpi.dsl.close_reason", CLOSE_REASON.EXCHANGE_SL_HIT);
103
117
  logger.info("[dsl] exchange SL filled, archiving position", {
104
118
  tickId,
105
119
  asset: state.asset,
@@ -145,10 +159,8 @@ export async function processOnePosition(ctx, key, state, price) {
145
159
  reason: closeReasonToUse,
146
160
  attempt: next.consecutiveCloseFailures,
147
161
  });
148
- const closeStartedAt = Date.now();
149
- let closeAttemptEmitted = false;
150
162
  try {
151
- const closeResult = await withRetry(() => strategy.closePosition(state.asset, closeReasonToUse, state.dex || undefined, {
163
+ const closeResult = await withSpan("dsl.close_attempt", { "senpi.dsl.attempt": next.consecutiveCloseFailures }, () => withRetry(() => strategy.closePosition(state.asset, closeReasonToUse, state.dex || undefined, {
152
164
  orderType: ctx.closeOrderType,
153
165
  feeOptimizedLimitOptions: ctx.feeOptimizedLimitOptions,
154
166
  }), {
@@ -156,22 +168,8 @@ export async function processOnePosition(ctx, key, state, price) {
156
168
  delayMs: DSL_EXTERNAL_RETRY_DELAY_MS,
157
169
  label: "closePosition (pendingClose)",
158
170
  onRetry: (attempt, remaining, err) => logger.warn("[dsl] closePosition retry", { asset: state.asset, attempt, remaining, err }),
159
- });
160
- // Telemetry-only fire-and-forget: the venue-call window for the dsl.close_attempt span.
161
- bus.emit("tracking.dsl_close_attempt", {
162
- tickId,
163
- key,
164
- asset: state.asset,
165
- dex,
166
- positionId: state.positionId ?? state.correlationId,
167
- startedAt: closeStartedAt,
168
- endedAt: Date.now(),
169
- outcome: "ok",
170
- closeReason: closeReasonToUse,
171
- attempt: next.consecutiveCloseFailures,
172
- timestamp: isoNow(),
173
- });
174
- closeAttemptEmitted = true;
171
+ }));
172
+ span.setAttribute("senpi.dsl.close_reason", closeReasonToUse);
175
173
  const closeFill = parseCloseFillDetail(closeResult);
176
174
  logger.info("[dsl] closePosition succeeded, archiving (pendingClose)", {
177
175
  tickId,
@@ -199,25 +197,6 @@ export async function processOnePosition(ctx, key, state, price) {
199
197
  }
200
198
  catch (e) {
201
199
  logger.warn("closePosition retry failed", { asset: state.asset, err: e });
202
- // Telemetry-only fire-and-forget: the failed venue-call window (dsl.close_attempt, error).
203
- // Guarded: when the ok emit already fired, the venue call itself succeeded — a later
204
- // state-write throw must not be misattributed to the venue.
205
- if (!closeAttemptEmitted) {
206
- bus.emit("tracking.dsl_close_attempt", {
207
- tickId,
208
- key,
209
- asset: state.asset,
210
- dex,
211
- positionId: state.positionId ?? state.correlationId,
212
- startedAt: closeStartedAt,
213
- endedAt: Date.now(),
214
- outcome: "error",
215
- closeReason: closeReasonToUse,
216
- attempt: next.consecutiveCloseFailures,
217
- error: String(e),
218
- timestamp: isoNow(),
219
- });
220
- }
221
200
  next.lastError = String(e);
222
201
  next.lastErrorAt = ts;
223
202
  const crossedThreshold = (next.consecutiveCloseFailures ?? 0) >= MAX_CONSECUTIVE_CLOSE_FAILURES;
@@ -249,7 +228,6 @@ export async function processOnePosition(ctx, key, state, price) {
249
228
  attempt: next.consecutiveCloseFailures,
250
229
  triggerReason: state.triggerReason,
251
230
  __positionId: state.positionId ?? state.correlationId,
252
- __correlationId: state.correlationId,
253
231
  timestamp: isoNow(),
254
232
  });
255
233
  }
@@ -259,18 +237,23 @@ export async function processOnePosition(ctx, key, state, price) {
259
237
  if (price == null) {
260
238
  const next = { ...state, consecutiveFetchFailures: (state.consecutiveFetchFailures ?? 0) + 1 };
261
239
  next.tickCount = (state.tickCount ?? 0) + 1;
240
+ // Edge-triggered: fire once when the streak first reaches the stale threshold (the alertable
241
+ // transition); the per-tick info line below covers ongoing visibility. A `>=` test (not `===`)
242
+ // latched on the state so a counter rehydrated at/above the threshold mid-stall (post-restart)
243
+ // still fires once; the priced-tick re-arm below clears the latch for the next stall.
244
+ const shouldEmitStale = next.consecutiveFetchFailures >= DSL_PRICE_FETCH_FAILURE_WARN_THRESHOLD &&
245
+ !state.priceFetchStaleEmitted;
246
+ if (shouldEmitStale)
247
+ next.priceFetchStaleEmitted = true;
262
248
  await setIfStillActive(stateManager, key, state.address, state.asset, (current) => ({
263
249
  ...current,
264
250
  consecutiveFetchFailures: (current.consecutiveFetchFailures ?? 0) + 1,
265
251
  tickCount: (current.tickCount ?? 0) + 1,
252
+ ...(shouldEmitStale ? { priceFetchStaleEmitted: true } : {}),
266
253
  }), { tickId, skipMessage: "[dsl] skip no-price counter write: state already cleared (concurrent close)" });
267
- if (next.consecutiveFetchFailures >= DSL_PRICE_FETCH_FAILURE_WARN_THRESHOLD) {
268
- logger.warn("[dsl] sustained price fetch failures for position", {
269
- tickId,
270
- key,
271
- asset: state.asset,
272
- consecutiveFetchFailures: next.consecutiveFetchFailures,
273
- });
254
+ if (shouldEmitStale) {
255
+ emitEvent(logger, () => buildPriceFetchStaleEvent(failureContext(state), next.consecutiveFetchFailures));
256
+ recordDslDegradation({ failure: "price_stale" });
274
257
  }
275
258
  logger.info("[dsl] monitor no price for position, skipping dslTick", {
276
259
  tickId,
@@ -281,8 +264,29 @@ export async function processOnePosition(ctx, key, state, price) {
281
264
  return;
282
265
  }
283
266
  const result = dslTick(state, price, ts);
267
+ if (result.floorChanged) {
268
+ span.addEvent("floorChanged", { "senpi.dsl.floor_price": result.state.floorPrice });
269
+ }
270
+ if (result.phaseChanged) {
271
+ span.addEvent("phaseChanged", { "senpi.dsl.phase": result.newPhase ?? 2 });
272
+ }
273
+ if (result.tierChanged && result.newTierIndex != null) {
274
+ span.addEvent("tier_advanced", { "senpi.dsl.tier_index": result.newTierIndex });
275
+ }
276
+ if ((result.state.currentBreachCount ?? 0) > (state.currentBreachCount ?? 0)) {
277
+ span.addEvent("breach_detected", {
278
+ count: result.state.currentBreachCount,
279
+ required: result.state.breachesRequired,
280
+ });
281
+ }
282
+ span.setAttribute("senpi.dsl.phase", result.state.phase);
283
+ if (result.state.currentTierIndex != null) {
284
+ span.setAttribute("senpi.dsl.tier_index", result.state.currentTierIndex);
285
+ }
284
286
  const next = { ...result.state };
285
287
  next.consecutiveFetchFailures = 0;
288
+ // Re-arm the stale-event latch: the price is back, so the next stall fires a fresh event.
289
+ next.priceFetchStaleEmitted = false;
286
290
  next.tickCount = (state.tickCount ?? 0) + 1;
287
291
  next.lastError = null;
288
292
  next.lastErrorAt = null;
@@ -314,6 +318,8 @@ export async function processOnePosition(ctx, key, state, price) {
314
318
  });
315
319
  if (result.action === "close") {
316
320
  const closeReasonToUse = result.closeReason ?? CLOSE_REASON.DSL_BREACH;
321
+ span.setAttribute("senpi.dsl.current_roe", next.currentROE);
322
+ span.setAttribute("senpi.dsl.floor_price", next.floorPrice);
317
323
  if (closeReasonToUse === CLOSE_REASON.DSL_BREACH && next.phase === 2) {
318
324
  logger.warn("[dsl] ignoring spurious dsl_breach close in phase 2 (exchange SL should exit)", {
319
325
  tickId,
@@ -333,9 +339,12 @@ export async function processOnePosition(ctx, key, state, price) {
333
339
  // If backend owns Phase 2, also delete the position on the backend
334
340
  if (next.handoffStatus === "ok" && next.backendDslPositionId && strategy) {
335
341
  try {
336
- await strategy.deleteRatchetStop({
337
- asset: state.asset,
338
- dex: state.dex || undefined,
342
+ await withSpan("dsl.handoff", { "senpi.dsl.handoff.op": "delete" }, async (handoffSpan) => {
343
+ await strategy.deleteRatchetStop({
344
+ asset: state.asset,
345
+ dex: state.dex || undefined,
346
+ });
347
+ handoffSpan.setAttribute("senpi.dsl.handoff.status", "ok");
339
348
  });
340
349
  logger.info("[dsl] deleted backend dsl position (global settings close)", {
341
350
  tickId,
@@ -353,10 +362,8 @@ export async function processOnePosition(ctx, key, state, price) {
353
362
  }
354
363
  }
355
364
  let closeFill = {};
356
- const closeStartedAt = Date.now();
357
- let closeAttemptEmitted = false;
358
365
  try {
359
- const closeResult = await withRetry(() => strategy.closePosition(state.asset, closeReasonToUse, state.dex || undefined, {
366
+ const closeResult = await withSpan("dsl.close_attempt", { "senpi.dsl.attempt": (next.consecutiveCloseFailures ?? 0) + 1 }, () => withRetry(() => strategy.closePosition(state.asset, closeReasonToUse, state.dex || undefined, {
360
367
  orderType: ctx.closeOrderType,
361
368
  feeOptimizedLimitOptions: ctx.feeOptimizedLimitOptions,
362
369
  }), {
@@ -364,23 +371,7 @@ export async function processOnePosition(ctx, key, state, price) {
364
371
  delayMs: DSL_EXTERNAL_RETRY_DELAY_MS,
365
372
  label: "closePosition (dsl breach/timeout)",
366
373
  onRetry: (attempt, remaining, err) => logger.warn("[dsl] closePosition retry", { asset: state.asset, attempt, remaining, err }),
367
- });
368
- // Telemetry-only fire-and-forget: the venue-call window for the dsl.close_attempt span.
369
- // Emitted before any post-venue work (fill parsing) so its outcome reflects the venue call alone.
370
- bus.emit("tracking.dsl_close_attempt", {
371
- tickId,
372
- key,
373
- asset: state.asset,
374
- dex,
375
- positionId: state.positionId ?? state.correlationId,
376
- startedAt: closeStartedAt,
377
- endedAt: Date.now(),
378
- outcome: "ok",
379
- closeReason: closeReasonToUse,
380
- attempt: (next.consecutiveCloseFailures ?? 0) + 1,
381
- timestamp: isoNow(),
382
- });
383
- closeAttemptEmitted = true;
374
+ }));
384
375
  closeFill = parseCloseFillDetail(closeResult);
385
376
  }
386
377
  catch (e) {
@@ -393,26 +384,9 @@ export async function processOnePosition(ctx, key, state, price) {
393
384
  lastError: String(e),
394
385
  lastErrorAt: ts,
395
386
  };
396
- // Telemetry-only fire-and-forget: the failed venue-call window (dsl.close_attempt, error).
397
- // Guarded: when the ok emit already fired, the venue call itself succeeded — a later
398
- // post-venue throw must not be misattributed to the venue.
399
- if (!closeAttemptEmitted) {
400
- bus.emit("tracking.dsl_close_attempt", {
401
- tickId,
402
- key,
403
- asset: state.asset,
404
- dex,
405
- positionId: state.positionId ?? state.correlationId,
406
- startedAt: closeStartedAt,
407
- endedAt: Date.now(),
408
- outcome: "error",
409
- closeReason: closeReasonToUse,
410
- attempt: pending.consecutiveCloseFailures,
411
- error: String(e),
412
- timestamp: isoNow(),
413
- });
414
- }
387
+ span.addEvent("pendingClose_set", { attempt: pending.consecutiveCloseFailures });
415
388
  if ((pending.consecutiveCloseFailures ?? 0) >= MAX_CONSECUTIVE_CLOSE_FAILURES) {
389
+ span.setAttribute("senpi.dsl.close_reason", CLOSE_REASON.CLOSE_POSITION_FAILED);
416
390
  const failedCloseState = { ...pending, active: false, closedAt: isoNow(), closeReason: CLOSE_REASON.CLOSE_POSITION_FAILED };
417
391
  const archived = await archiveIfStillActive(stateManager, key, state.address, state.asset, effectiveDex(state), () => failedCloseState, { tickId, skipMessage: "[dsl] skip breach close-fail archive: state already cleared (concurrent close)" });
418
392
  if (!archived)
@@ -440,12 +414,12 @@ export async function processOnePosition(ctx, key, state, price) {
440
414
  attempt: pending.consecutiveCloseFailures,
441
415
  triggerReason: state.triggerReason,
442
416
  __positionId: state.positionId ?? state.correlationId,
443
- __correlationId: state.correlationId,
444
417
  timestamp: isoNow(),
445
418
  });
446
419
  }
447
420
  return;
448
421
  }
422
+ span.setAttribute("senpi.dsl.close_reason", closeReasonToUse);
449
423
  logger.info("[dsl] closePosition succeeded, archiving (dsl breach/timeout)", {
450
424
  tickId,
451
425
  asset: state.asset,
@@ -488,7 +462,6 @@ export async function processOnePosition(ctx, key, state, price) {
488
462
  newFloorPrice: dslEffectiveFloor,
489
463
  triggerReason: next.triggerReason,
490
464
  __positionId: next.positionId ?? next.correlationId,
491
- __correlationId: next.correlationId,
492
465
  timestamp: ts,
493
466
  direction: next.direction,
494
467
  entryPrice: next.entryPrice,
@@ -519,13 +492,12 @@ export async function processOnePosition(ctx, key, state, price) {
519
492
  tierIndex: result.newTierIndex ?? 0,
520
493
  triggerReason: next.triggerReason,
521
494
  __positionId: next.positionId ?? next.correlationId,
522
- __correlationId: next.correlationId,
523
495
  timestamp: ts,
524
496
  });
525
497
  }
526
498
  }
527
499
  if (next.handoffStatus === "ok" && strategy) {
528
- await handleHandoffOk(ctx, key, next, state, strategy);
500
+ await handleHandoffOk(ctx, key, next, state, strategy, span);
529
501
  return;
530
502
  }
531
503
  // Catch-up: if position is already in Phase 2 but handoff was never attempted,
@@ -585,39 +557,22 @@ export async function processOnePosition(ctx, key, state, price) {
585
557
  phaseChanged: result.phaseChanged,
586
558
  prevSlOrderId: next.slOrderId,
587
559
  });
588
- const slSyncStartedAt = Date.now();
589
- let slUpdateEmitted = false;
590
560
  try {
591
- const res = await withRetry(() => strategy.editPosition({
592
- coin: state.asset,
593
- dex: state.dex || undefined,
594
- stopLoss: { triggerPx: exchangeTriggerPx },
595
- }), {
596
- retries: DSL_EXTERNAL_RETRIES,
597
- delayMs: DSL_EXTERNAL_RETRY_DELAY_MS,
598
- label: "editPosition (SL sync)",
599
- onRetry: (attempt, remaining, err) => logger.warn("[dsl] editPosition retry", { asset: state.asset, attempt, remaining, err }),
600
- });
601
- const slSyncEndedAt = Date.now();
602
- // Telemetry-only fire-and-forget: the venue-call window for the dsl.sl_update span. Emitted
603
- // immediately after the venue call resolves — before any state read/write — so it fires even
604
- // when a concurrent close returns early below, and reports the venue's own answer
605
- // (`res.slOrderId`), the honest venue-call fact.
606
- bus.emit("tracking.dsl_sl_update", {
607
- tickId,
608
- key,
609
- asset: state.asset,
610
- dex,
611
- positionId: state.positionId ?? state.correlationId,
612
- startedAt: slSyncStartedAt,
613
- endedAt: slSyncEndedAt,
614
- outcome: "ok",
615
- newSLPrice: exchangeTriggerPx,
616
- slOrderId: res.slOrderId,
617
- syncReason,
618
- timestamp: isoNow(),
561
+ const res = await withSpan("dsl.sl_update", {}, async (slSpan) => {
562
+ const r = await withRetry(() => strategy.editPosition({
563
+ coin: state.asset,
564
+ dex: state.dex || undefined,
565
+ stopLoss: { triggerPx: exchangeTriggerPx },
566
+ }), {
567
+ retries: DSL_EXTERNAL_RETRIES,
568
+ delayMs: DSL_EXTERNAL_RETRY_DELAY_MS,
569
+ label: "editPosition (SL sync)",
570
+ onRetry: (attempt, remaining, err) => logger.warn("[dsl] editPosition retry", { asset: state.asset, attempt, remaining, err }),
571
+ });
572
+ if (r.slOrderId != null)
573
+ slSpan.setAttribute("senpi.order.id", String(r.slOrderId));
574
+ return r;
619
575
  });
620
- slUpdateEmitted = true;
621
576
  let syncedForEmit = null;
622
577
  await setIfStillActive(stateManager, key, state.address, state.asset, (current) => {
623
578
  const synced = {
@@ -651,30 +606,10 @@ export async function processOnePosition(ctx, key, state, price) {
651
606
  slOrderId: synced.slOrderId ?? 0,
652
607
  triggerReason: synced.triggerReason,
653
608
  __positionId: synced.positionId ?? synced.correlationId,
654
- __correlationId: synced.correlationId,
655
609
  timestamp: ts,
656
610
  });
657
611
  }
658
612
  catch (e) {
659
- // Telemetry-only fire-and-forget: the failed venue-call window (dsl.sl_update, error).
660
- // Guarded: when the ok emit already fired, the venue call itself succeeded — a later
661
- // state-write throw must not be misattributed to the venue.
662
- if (!slUpdateEmitted) {
663
- bus.emit("tracking.dsl_sl_update", {
664
- tickId,
665
- key,
666
- asset: state.asset,
667
- dex,
668
- positionId: state.positionId ?? state.correlationId,
669
- startedAt: slSyncStartedAt,
670
- endedAt: Date.now(),
671
- outcome: "error",
672
- newSLPrice: exchangeTriggerPx,
673
- syncReason,
674
- error: String(e),
675
- timestamp: isoNow(),
676
- });
677
- }
678
613
  let syncFailureCount = null;
679
614
  await setIfStillActive(stateManager, key, state.address, state.asset, (current) => {
680
615
  syncFailureCount = (current.slSyncFailureCount ?? 0) + 1;
@@ -688,14 +623,8 @@ export async function processOnePosition(ctx, key, state, price) {
688
623
  }, { tickId, skipMessage: "[dsl] skip SL sync-failure write: state no longer active (concurrent close)" });
689
624
  if (syncFailureCount == null)
690
625
  return;
691
- logger.warn("[dsl] editPosition (SL update) failed", {
692
- tickId,
693
- asset: state.asset,
694
- exchangeTriggerPx,
695
- dslEffectiveFloor,
696
- slSyncFailureCount: syncFailureCount,
697
- err: e,
698
- });
626
+ emitEvent(logger, () => buildSlSyncFailedEvent(failureContext(state), syncFailureCount ?? 0, e));
627
+ recordDslDegradation({ failure: "sl_sync", errorType: errorTypeOf(e) });
699
628
  }
700
629
  }
701
630
  const hbState = await stateManager.getOrLoad(key);
@@ -728,7 +657,6 @@ export async function processOnePosition(ctx, key, state, price) {
728
657
  elapsedMinutes: hbState.elapsedMinutes,
729
658
  triggerReason: hbState.triggerReason,
730
659
  __positionId: hbState.positionId ?? hbState.correlationId,
731
- __correlationId: hbState.correlationId,
732
660
  margin: hbState.leverage > 0
733
661
  ? (hbState.size * hbState.entryPrice) / hbState.leverage
734
662
  : 0,
@@ -765,11 +693,11 @@ async function attemptHandoffRegistration(ctx, key, next, _original, strategy) {
765
693
  // attempt succeeded but we never persisted "ok"), adopt it instead of
766
694
  // sending another addRatchetStop that the backend turns into an EDIT.
767
695
  try {
768
- const existing = await strategy.queryRatchetStops({
696
+ const existing = await withSpan("dsl.handoff", { "senpi.dsl.handoff.op": "register_precheck" }, () => strategy.queryRatchetStops({
769
697
  asset: next.asset,
770
698
  dex: next.dex || undefined,
771
699
  status: "ALL",
772
- });
700
+ }));
773
701
  const active = existing.filter((p) => !BACKEND_TERMINAL_STATUSES.has(p.status));
774
702
  if (active.length > 0) {
775
703
  const adopted = active[0];
@@ -802,18 +730,24 @@ async function attemptHandoffRegistration(ctx, key, next, _original, strategy) {
802
730
  });
803
731
  }
804
732
  try {
805
- const result = await strategy.addRatchetStop({
806
- asset: next.asset,
807
- dex: next.dex || undefined,
808
- direction: next.direction,
809
- entryPrice: next.entryPrice,
810
- size: next.size,
811
- leverage: next.leverage,
812
- ratchetStopConfig: {
813
- tiered: {
814
- tiers: mapTiersToEngineConfig(next.tiers),
733
+ const result = await withSpan("dsl.handoff", { "senpi.dsl.handoff.op": "register" }, async (handoffSpan) => {
734
+ const r = await strategy.addRatchetStop({
735
+ asset: next.asset,
736
+ dex: next.dex || undefined,
737
+ direction: next.direction,
738
+ entryPrice: next.entryPrice,
739
+ size: next.size,
740
+ leverage: next.leverage,
741
+ ratchetStopConfig: {
742
+ tiered: {
743
+ tiers: mapTiersToEngineConfig(next.tiers),
744
+ },
815
745
  },
816
- },
746
+ });
747
+ if (r.success && r.position) {
748
+ handoffSpan.setAttribute("senpi.dsl.handoff.status", BACKEND_TERMINAL_STATUSES.has(r.position.status) ? "aborted" : "ok");
749
+ }
750
+ return r;
817
751
  });
818
752
  if (result.success && result.position) {
819
753
  if (BACKEND_TERMINAL_STATUSES.has(result.position.status)) {
@@ -854,22 +788,19 @@ async function attemptHandoffRegistration(ctx, key, next, _original, strategy) {
854
788
  });
855
789
  }
856
790
  else {
857
- logger.warn("[dsl] addDslPosition returned success=false, staying pending", {
858
- tickId,
859
- asset: next.asset,
860
- rawResult: JSON.stringify(result).slice(0, 800),
861
- });
791
+ emitEvent(logger, () => buildHandoffFailedEvent(failureContext(next), {
792
+ failure: "register",
793
+ redact: { result: JSON.stringify(result).slice(0, 800) },
794
+ }));
795
+ recordDslDegradation({ failure: "handoff", handoffFailure: "register" });
862
796
  }
863
797
  }
864
798
  catch (e) {
865
- logger.warn("[dsl] addDslPosition failed, staying pending (will retry next tick)", {
866
- tickId,
867
- asset: next.asset,
868
- err: e,
869
- });
799
+ emitEvent(logger, () => buildHandoffFailedEvent(failureContext(next), { failure: "register", error: e }));
800
+ recordDslDegradation({ failure: "handoff", handoffFailure: "register", errorType: errorTypeOf(e) });
870
801
  }
871
802
  }
872
- async function handleHandoffOk(ctx, key, next, original, strategy) {
803
+ async function handleHandoffOk(ctx, key, next, original, strategy, span) {
873
804
  const { tickId, ts, stateManager, bus } = ctx;
874
805
  let updated = { ...next };
875
806
  // Snapshot pre-merge state so we can detect backend event echoes for tier/SL
@@ -877,24 +808,22 @@ async function handleHandoffOk(ctx, key, next, original, strategy) {
877
808
  const prevTierIndex = updated.currentTierIndex;
878
809
  const prevSlOrderId = updated.slOrderId;
879
810
  try {
880
- const positions = await strategy.queryRatchetStops({
811
+ const positions = await withSpan("dsl.handoff", { "senpi.dsl.handoff.op": "poll_positions" }, () => strategy.queryRatchetStops({
881
812
  asset: original.asset,
882
813
  dex: original.dex || undefined,
883
814
  status: "ALL",
884
- });
815
+ }));
885
816
  const backendPos = next.backendDslPositionId
886
817
  ? positions.find((p) => p.id === next.backendDslPositionId) ?? null
887
818
  : positions.filter((p) => !BACKEND_TERMINAL_STATUSES.has(p.status)).length === 1
888
819
  ? positions.filter((p) => !BACKEND_TERMINAL_STATUSES.has(p.status))[0]
889
820
  : null;
890
821
  if (!backendPos) {
891
- logger.warn("[dsl] handoff ok but matching backend position not found, reverting to local Phase 2", {
892
- tickId,
893
- key,
894
- asset: original.asset,
895
- backendDslPositionId: next.backendDslPositionId,
896
- returnedIds: positions.map((p) => p.id),
897
- });
822
+ emitEvent(logger, () => buildHandoffFailedEvent(failureContext(original), {
823
+ failure: "rollback",
824
+ backendPositionId: next.backendDslPositionId ?? undefined,
825
+ }));
826
+ recordDslDegradation({ failure: "handoff", handoffFailure: "rollback" });
898
827
  const rolledBack = {
899
828
  ...updated,
900
829
  handoffStatus: null,
@@ -906,12 +835,14 @@ async function handleHandoffOk(ctx, key, next, original, strategy) {
906
835
  }
907
836
  else {
908
837
  if (BACKEND_TERMINAL_STATUSES.has(backendPos.status)) {
838
+ span.addEvent("external_close_detected", { source: "backend_terminal" });
909
839
  logger.info("[dsl] backend reports terminal status, closing position locally", {
910
840
  tickId,
911
841
  asset: original.asset,
912
842
  backendStatus: backendPos.status,
913
843
  });
914
844
  const closeReason = `backend_${backendPos.status.toLowerCase()}`;
845
+ span.setAttribute("senpi.dsl.close_reason", closeReason);
915
846
  const closedState = {
916
847
  ...updated,
917
848
  active: false,
@@ -943,20 +874,21 @@ async function handleHandoffOk(ctx, key, next, original, strategy) {
943
874
  }
944
875
  }
945
876
  catch (e) {
946
- logger.warn("[dsl] queryPositions failed during handoff poll", {
947
- tickId,
948
- asset: original.asset,
949
- err: e,
950
- });
877
+ emitEvent(logger, () => buildHandoffFailedEvent(failureContext(original), {
878
+ failure: "poll",
879
+ backendPositionId: next.backendDslPositionId ?? undefined,
880
+ error: e,
881
+ }));
882
+ recordDslDegradation({ failure: "handoff", handoffFailure: "poll", errorType: errorTypeOf(e) });
951
883
  }
952
884
  try {
953
885
  // ASC ordering is required: the cursor advances to the LAST element of the array
954
886
  // below, which must be the newest event. Backend default is DESC.
955
- const events = await strategy.queryRatchetStopEvents({
887
+ const events = await withSpan("dsl.handoff", { "senpi.dsl.handoff.op": "poll_events" }, () => strategy.queryRatchetStopEvents({
956
888
  positionId: updated.backendDslPositionId ?? undefined,
957
889
  since: updated.lastBackendDslTick ?? undefined,
958
890
  sortOrder: "ASC",
959
- });
891
+ }));
960
892
  // Filter out events already seen on the previous poll (since may be inclusive)
961
893
  const cursor = updated.lastBackendDslTick;
962
894
  const freshEvents = cursor
@@ -1037,7 +969,9 @@ async function handleHandoffOk(ctx, key, next, original, strategy) {
1037
969
  });
1038
970
  // Archive local state when backend reports position closed via event stream
1039
971
  if (backendClosed) {
972
+ span.addEvent("external_close_detected", { source: "backend_terminal" });
1040
973
  const closeReason = backendCloseReason ?? "backend_closed";
974
+ span.setAttribute("senpi.dsl.close_reason", closeReason);
1041
975
  logger.info("[dsl] backend CLOSED event received, archiving local state", {
1042
976
  tickId,
1043
977
  key,