@senpi/runtime 3.0.6-dev.skill-manager-v2.20260629194505 → 3.0.9-dev.20260710204324
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.
- package/dist/actions/action-events.d.ts +67 -0
- package/dist/actions/action-events.d.ts.map +1 -0
- package/dist/actions/action-events.js +164 -0
- package/dist/actions/action-events.js.map +1 -0
- package/dist/actions/close-position/close-position.action.d.ts +1 -1
- package/dist/actions/close-position/close-position.action.d.ts.map +1 -1
- package/dist/actions/close-position/close-position.action.js +108 -86
- package/dist/actions/close-position/close-position.action.js.map +1 -1
- package/dist/actions/decision-engine.d.ts.map +1 -1
- package/dist/actions/decision-engine.js +40 -28
- package/dist/actions/decision-engine.js.map +1 -1
- package/dist/actions/event-derivation.d.ts +61 -0
- package/dist/actions/event-derivation.d.ts.map +1 -0
- package/dist/actions/event-derivation.js +180 -0
- package/dist/actions/event-derivation.js.map +1 -0
- package/dist/actions/llm-decision/anthropic-llm-decision.d.ts +5 -9
- package/dist/actions/llm-decision/anthropic-llm-decision.d.ts.map +1 -1
- package/dist/actions/llm-decision/anthropic-llm-decision.js +6 -87
- package/dist/actions/llm-decision/anthropic-llm-decision.js.map +1 -1
- package/dist/actions/llm-decision/factory.d.ts +0 -6
- package/dist/actions/llm-decision/factory.d.ts.map +1 -1
- package/dist/actions/llm-decision/factory.js +0 -2
- package/dist/actions/llm-decision/factory.js.map +1 -1
- package/dist/actions/llm-decision/openclaw-llm-decision.d.ts.map +1 -1
- package/dist/actions/llm-decision/openclaw-llm-decision.js +26 -7
- package/dist/actions/llm-decision/openclaw-llm-decision.js.map +1 -1
- package/dist/actions/open-position/open-position.action.d.ts +1 -1
- package/dist/actions/open-position/open-position.action.d.ts.map +1 -1
- package/dist/actions/open-position/open-position.action.js +282 -224
- package/dist/actions/open-position/open-position.action.js.map +1 -1
- package/dist/actions/position-tracker/position-tracker.action.d.ts.map +1 -1
- package/dist/actions/position-tracker/position-tracker.action.js +3 -6
- package/dist/actions/position-tracker/position-tracker.action.js.map +1 -1
- package/dist/cli/guide-commands.d.ts.map +1 -1
- package/dist/cli/guide-commands.js +61 -0
- package/dist/cli/guide-commands.js.map +1 -1
- package/dist/cli/senpi-commands.d.ts +14 -0
- package/dist/cli/senpi-commands.d.ts.map +1 -1
- package/dist/cli/senpi-commands.js +390 -2
- package/dist/cli/senpi-commands.js.map +1 -1
- package/dist/dsl/engine-client/event-mapping.d.ts.map +1 -1
- package/dist/dsl/engine-client/event-mapping.js +0 -3
- package/dist/dsl/engine-client/event-mapping.js.map +1 -1
- package/dist/dsl/events/build-closed-event.d.ts.map +1 -1
- package/dist/dsl/events/build-closed-event.js +0 -1
- package/dist/dsl/events/build-closed-event.js.map +1 -1
- package/dist/dsl/events/handlers.d.ts.map +1 -1
- package/dist/dsl/events/handlers.js +2 -4
- package/dist/dsl/events/handlers.js.map +1 -1
- package/dist/dsl/events/initial-state.d.ts.map +1 -1
- package/dist/dsl/events/initial-state.js +1 -0
- package/dist/dsl/events/initial-state.js.map +1 -1
- package/dist/dsl/monitor/create-monitor.d.ts +3 -0
- package/dist/dsl/monitor/create-monitor.d.ts.map +1 -1
- package/dist/dsl/monitor/create-monitor.js +76 -58
- package/dist/dsl/monitor/create-monitor.js.map +1 -1
- package/dist/dsl/monitor/dsl-failure-events.d.ts +42 -0
- package/dist/dsl/monitor/dsl-failure-events.d.ts.map +1 -0
- package/dist/dsl/monitor/dsl-failure-events.js +73 -0
- package/dist/dsl/monitor/dsl-failure-events.js.map +1 -0
- package/dist/dsl/monitor/process-one-position.d.ts +2 -1
- package/dist/dsl/monitor/process-one-position.d.ts.map +1 -1
- package/dist/dsl/monitor/process-one-position.js +130 -196
- package/dist/dsl/monitor/process-one-position.js.map +1 -1
- package/dist/dsl/plugin/index.d.ts +10 -0
- package/dist/dsl/plugin/index.d.ts.map +1 -1
- package/dist/dsl/plugin/index.js +48 -4
- package/dist/dsl/plugin/index.js.map +1 -1
- package/dist/dsl/plugin/options.d.ts +3 -0
- package/dist/dsl/plugin/options.d.ts.map +1 -1
- package/dist/health/types.d.ts +14 -0
- package/dist/health/types.d.ts.map +1 -1
- package/dist/health/types.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +264 -79
- package/dist/index.js.map +1 -1
- package/dist/risk/risk-audit-log.d.ts +7 -0
- package/dist/risk/risk-audit-log.d.ts.map +1 -1
- package/dist/risk/risk-audit-log.js +48 -1
- package/dist/risk/risk-audit-log.js.map +1 -1
- package/dist/runtime/__tests__/helpers/runtime-gateway-harness.d.ts +2 -0
- package/dist/runtime/__tests__/helpers/runtime-gateway-harness.d.ts.map +1 -1
- package/dist/runtime/__tests__/helpers/runtime-gateway-harness.js +24 -3
- package/dist/runtime/__tests__/helpers/runtime-gateway-harness.js.map +1 -1
- package/dist/runtime/auto-update/coordinator.js +2 -2
- package/dist/runtime/auto-update/coordinator.js.map +1 -1
- package/dist/runtime/create-actions.d.ts.map +1 -1
- package/dist/runtime/create-actions.js +40 -15
- package/dist/runtime/create-actions.js.map +1 -1
- package/dist/runtime/create-runtime-context.d.ts +1 -1
- package/dist/runtime/create-runtime-context.d.ts.map +1 -1
- package/dist/runtime/create-scanner-module.d.ts +2 -1
- package/dist/runtime/create-scanner-module.d.ts.map +1 -1
- package/dist/runtime/create-scanner-module.js +2 -1
- package/dist/runtime/create-scanner-module.js.map +1 -1
- package/dist/runtime/domain-events.d.ts +43 -0
- package/dist/runtime/domain-events.d.ts.map +1 -0
- package/dist/runtime/domain-events.js +181 -0
- package/dist/runtime/domain-events.js.map +1 -0
- package/dist/runtime/lifecycle-events.d.ts +86 -0
- package/dist/runtime/lifecycle-events.d.ts.map +1 -0
- package/dist/runtime/lifecycle-events.js +200 -0
- package/dist/runtime/lifecycle-events.js.map +1 -0
- package/dist/runtime/notifications.js +2 -2
- package/dist/runtime/notifications.js.map +1 -1
- package/dist/{tracking → runtime}/position-id-registry.d.ts +14 -1
- package/dist/runtime/position-id-registry.d.ts.map +1 -0
- package/dist/{tracking → runtime}/position-id-registry.js +20 -3
- package/dist/runtime/position-id-registry.js.map +1 -0
- package/dist/runtime/run.d.ts +2 -4
- package/dist/runtime/run.d.ts.map +1 -1
- package/dist/runtime/run.js.map +1 -1
- package/dist/runtime/runtime-schema.d.ts +276 -588
- package/dist/runtime/runtime-schema.d.ts.map +1 -1
- package/dist/runtime/runtime-schema.js +8 -28
- package/dist/runtime/runtime-schema.js.map +1 -1
- package/dist/runtime/runtime.d.ts +23 -9
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +276 -248
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/strategy-lifecycle.d.ts.map +1 -1
- package/dist/runtime/strategy-lifecycle.js +13 -1
- package/dist/runtime/strategy-lifecycle.js.map +1 -1
- package/dist/runtime/supervisor/long-running-supervisor.d.ts +3 -0
- package/dist/runtime/supervisor/long-running-supervisor.d.ts.map +1 -1
- package/dist/runtime/supervisor/long-running-supervisor.js +27 -53
- package/dist/runtime/supervisor/long-running-supervisor.js.map +1 -1
- package/dist/runtime-api/config.d.ts +2 -2
- package/dist/runtime-api/config.js +4 -4
- package/dist/runtime-api/config.js.map +1 -1
- package/dist/runtime-api/handlers/ingest-signals.d.ts +5 -3
- package/dist/runtime-api/handlers/ingest-signals.d.ts.map +1 -1
- package/dist/runtime-api/handlers/ingest-signals.js +14 -5
- package/dist/runtime-api/handlers/ingest-signals.js.map +1 -1
- package/dist/runtime-api/intake/ingest-mutex.d.ts +16 -0
- package/dist/runtime-api/intake/ingest-mutex.d.ts.map +1 -0
- package/dist/runtime-api/intake/ingest-mutex.js +18 -0
- package/dist/runtime-api/intake/ingest-mutex.js.map +1 -0
- package/dist/runtime-api/intake/intake-events.d.ts +44 -0
- package/dist/runtime-api/intake/intake-events.d.ts.map +1 -0
- package/dist/runtime-api/intake/intake-events.js +131 -0
- package/dist/runtime-api/intake/intake-events.js.map +1 -0
- package/dist/runtime-api/intake/intake-mount.d.ts.map +1 -1
- package/dist/runtime-api/intake/intake-mount.js +8 -2
- package/dist/runtime-api/intake/intake-mount.js.map +1 -1
- package/dist/runtime-api/intake/scanner-launcher.d.ts +2 -0
- package/dist/runtime-api/intake/scanner-launcher.d.ts.map +1 -1
- package/dist/runtime-api/intake/scanner-launcher.js +58 -15
- package/dist/runtime-api/intake/scanner-launcher.js.map +1 -1
- package/dist/runtime-api/intake/scanner-registry.d.ts +3 -0
- package/dist/runtime-api/intake/scanner-registry.d.ts.map +1 -1
- package/dist/runtime-api/intake/scanner-registry.js +3 -0
- package/dist/runtime-api/intake/scanner-registry.js.map +1 -1
- package/dist/runtime-api/intake/supervisor-events.d.ts +61 -0
- package/dist/runtime-api/intake/supervisor-events.d.ts.map +1 -0
- package/dist/runtime-api/intake/supervisor-events.js +173 -0
- package/dist/runtime-api/intake/supervisor-events.js.map +1 -0
- package/dist/runtime-api/routes/signals.d.ts +1 -1
- package/dist/runtime-api/routes/signals.d.ts.map +1 -1
- package/dist/runtime-api/routes/signals.js +121 -35
- package/dist/runtime-api/routes/signals.js.map +1 -1
- package/dist/runtime-api/server.d.ts.map +1 -1
- package/dist/runtime-api/server.js +10 -1
- package/dist/runtime-api/server.js.map +1 -1
- package/dist/scanners/engine/data-providers.d.ts +3 -0
- package/dist/scanners/engine/data-providers.d.ts.map +1 -1
- package/dist/scanners/engine/data-providers.js.map +1 -1
- package/dist/scanners/engine/engine.d.ts +18 -0
- package/dist/scanners/engine/engine.d.ts.map +1 -1
- package/dist/scanners/engine/engine.js +96 -2
- package/dist/scanners/engine/engine.js.map +1 -1
- package/dist/scanners/engine/input-resolver.d.ts.map +1 -1
- package/dist/scanners/engine/input-resolver.js +9 -7
- package/dist/scanners/engine/input-resolver.js.map +1 -1
- package/dist/scanners/runtime-module.d.ts +3 -0
- package/dist/scanners/runtime-module.d.ts.map +1 -1
- package/dist/scanners/runtime-module.js +7 -0
- package/dist/scanners/runtime-module.js.map +1 -1
- package/dist/senpi/client.d.ts +10 -0
- package/dist/senpi/client.d.ts.map +1 -1
- package/dist/senpi/client.js +113 -46
- package/dist/senpi/client.js.map +1 -1
- package/dist/skills-manager/bootstrap.d.ts.map +1 -1
- package/dist/skills-manager/bootstrap.js +22 -33
- package/dist/skills-manager/bootstrap.js.map +1 -1
- package/dist/skills-manager/clone-groups.d.ts +20 -0
- package/dist/skills-manager/clone-groups.d.ts.map +1 -0
- package/dist/skills-manager/clone-groups.js +45 -0
- package/dist/skills-manager/clone-groups.js.map +1 -0
- package/dist/skills-manager/coordinator.d.ts.map +1 -1
- package/dist/skills-manager/coordinator.js +111 -75
- package/dist/skills-manager/coordinator.js.map +1 -1
- package/dist/skills-manager/manifest.d.ts +24 -0
- package/dist/skills-manager/manifest.d.ts.map +1 -1
- package/dist/skills-manager/manifest.js +23 -10
- package/dist/skills-manager/manifest.js.map +1 -1
- package/dist/skills-manager/skills-manifest.json +12 -7
- package/dist/skills-manager/types.d.ts +12 -0
- package/dist/skills-manager/types.d.ts.map +1 -1
- package/dist/state/state-events.d.ts +13 -0
- package/dist/state/state-events.d.ts.map +1 -0
- package/dist/state/state-events.js +22 -0
- package/dist/state/state-events.js.map +1 -0
- package/dist/state/state-manager.d.ts.map +1 -1
- package/dist/state/state-manager.js +14 -1
- package/dist/state/state-manager.js.map +1 -1
- package/dist/telemetry/attributes.d.ts +13 -0
- package/dist/telemetry/attributes.d.ts.map +1 -0
- package/dist/telemetry/attributes.js +22 -0
- package/dist/telemetry/attributes.js.map +1 -0
- package/dist/{tracking → telemetry}/context.d.ts +12 -5
- package/dist/telemetry/context.d.ts.map +1 -0
- package/dist/{tracking → telemetry}/context.js +4 -4
- package/dist/telemetry/context.js.map +1 -0
- package/dist/{recording/records.d.ts → telemetry/event-builders.d.ts} +145 -33
- package/dist/telemetry/event-builders.d.ts.map +1 -0
- package/dist/{recording/wiring/record-builders.js → telemetry/event-builders.js} +94 -40
- package/dist/telemetry/event-builders.js.map +1 -0
- package/dist/telemetry/event-store.d.ts +66 -0
- package/dist/telemetry/event-store.d.ts.map +1 -0
- package/dist/telemetry/event-store.js +202 -0
- package/dist/telemetry/event-store.js.map +1 -0
- package/dist/telemetry/identity.d.ts +72 -0
- package/dist/telemetry/identity.d.ts.map +1 -0
- package/dist/{recording/wiring → telemetry}/identity.js +6 -2
- package/dist/telemetry/identity.js.map +1 -0
- package/dist/telemetry/metrics.d.ts +169 -0
- package/dist/telemetry/metrics.d.ts.map +1 -0
- package/dist/telemetry/metrics.js +437 -0
- package/dist/telemetry/metrics.js.map +1 -0
- package/dist/telemetry/otel-sdk.d.ts +93 -0
- package/dist/telemetry/otel-sdk.d.ts.map +1 -0
- package/dist/telemetry/otel-sdk.js +297 -0
- package/dist/telemetry/otel-sdk.js.map +1 -0
- package/dist/telemetry/spans/constants.d.ts +12 -0
- package/dist/telemetry/spans/constants.d.ts.map +1 -0
- package/dist/telemetry/spans/constants.js +12 -0
- package/dist/telemetry/spans/constants.js.map +1 -0
- package/dist/telemetry/spans/gen-ai.d.ts +74 -0
- package/dist/telemetry/spans/gen-ai.d.ts.map +1 -0
- package/dist/telemetry/spans/gen-ai.js +339 -0
- package/dist/telemetry/spans/gen-ai.js.map +1 -0
- package/dist/telemetry/spans/index.d.ts +11 -0
- package/dist/telemetry/spans/index.d.ts.map +1 -0
- package/dist/telemetry/spans/index.js +11 -0
- package/dist/telemetry/spans/index.js.map +1 -0
- package/dist/{tracking → telemetry}/spans/redact-pii.d.ts +19 -21
- package/dist/telemetry/spans/redact-pii.d.ts.map +1 -0
- package/dist/{tracking → telemetry}/spans/redact-pii.js +35 -32
- package/dist/telemetry/spans/redact-pii.js.map +1 -0
- package/dist/telemetry/spans/sanitize-payload.d.ts.map +1 -0
- package/dist/telemetry/spans/sanitize-payload.js.map +1 -0
- package/dist/telemetry/spans/span-hooks.d.ts +18 -0
- package/dist/telemetry/spans/span-hooks.d.ts.map +1 -0
- package/dist/telemetry/spans/span-hooks.js +764 -0
- package/dist/telemetry/spans/span-hooks.js.map +1 -0
- package/dist/telemetry/tool-plane.d.ts +31 -0
- package/dist/telemetry/tool-plane.d.ts.map +1 -0
- package/dist/telemetry/tool-plane.js +70 -0
- package/dist/telemetry/tool-plane.js.map +1 -0
- package/dist/telemetry/trace-identity.d.ts +32 -0
- package/dist/telemetry/trace-identity.d.ts.map +1 -0
- package/dist/telemetry/trace-identity.js +62 -0
- package/dist/telemetry/trace-identity.js.map +1 -0
- package/dist/telemetry/tracing.d.ts +33 -0
- package/dist/telemetry/tracing.d.ts.map +1 -0
- package/dist/telemetry/tracing.js +70 -0
- package/dist/telemetry/tracing.js.map +1 -0
- package/dist/types/dsl/index.d.ts +8 -9
- package/dist/types/dsl/index.d.ts.map +1 -1
- package/dist/types/runtime.d.ts +1 -1
- package/dist/types/runtime.d.ts.map +1 -1
- package/dist/types/scanner.d.ts +2 -0
- package/dist/types/scanner.d.ts.map +1 -1
- package/dist/utils/event-catalog.d.ts +506 -0
- package/dist/utils/event-catalog.d.ts.map +1 -0
- package/dist/utils/event-catalog.js +142 -0
- package/dist/utils/event-catalog.js.map +1 -0
- package/dist/utils/logger.d.ts +63 -5
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +360 -27
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/wallet-address.d.ts +3 -0
- package/dist/utils/wallet-address.d.ts.map +1 -0
- package/dist/utils/wallet-address.js +17 -0
- package/dist/utils/wallet-address.js.map +1 -0
- package/openclaw.plugin.json +20 -6
- package/package.json +10 -2
- package/dist/actions/tracking-helpers.d.ts +0 -28
- package/dist/actions/tracking-helpers.d.ts.map +0 -1
- package/dist/actions/tracking-helpers.js +0 -93
- package/dist/actions/tracking-helpers.js.map +0 -1
- package/dist/recording/emitter.d.ts +0 -27
- package/dist/recording/emitter.d.ts.map +0 -1
- package/dist/recording/emitter.js +0 -2
- package/dist/recording/emitter.js.map +0 -1
- package/dist/recording/identity.d.ts +0 -34
- package/dist/recording/identity.d.ts.map +0 -1
- package/dist/recording/identity.js +0 -2
- package/dist/recording/identity.js.map +0 -1
- package/dist/recording/index.d.ts +0 -11
- package/dist/recording/index.d.ts.map +0 -1
- package/dist/recording/index.js +0 -2
- package/dist/recording/index.js.map +0 -1
- package/dist/recording/noop-emitter.d.ts +0 -23
- package/dist/recording/noop-emitter.d.ts.map +0 -1
- package/dist/recording/noop-emitter.js +0 -22
- package/dist/recording/noop-emitter.js.map +0 -1
- package/dist/recording/otel/attributes.d.ts +0 -35
- package/dist/recording/otel/attributes.d.ts.map +0 -1
- package/dist/recording/otel/attributes.js +0 -131
- package/dist/recording/otel/attributes.js.map +0 -1
- package/dist/recording/otel/constants.d.ts +0 -123
- package/dist/recording/otel/constants.d.ts.map +0 -1
- package/dist/recording/otel/constants.js +0 -172
- package/dist/recording/otel/constants.js.map +0 -1
- package/dist/recording/otel/ids.d.ts +0 -25
- package/dist/recording/otel/ids.d.ts.map +0 -1
- package/dist/recording/otel/ids.js +0 -37
- package/dist/recording/otel/ids.js.map +0 -1
- package/dist/recording/otel/index.d.ts +0 -13
- package/dist/recording/otel/index.d.ts.map +0 -1
- package/dist/recording/otel/index.js +0 -9
- package/dist/recording/otel/index.js.map +0 -1
- package/dist/recording/otel/mappers.d.ts +0 -100
- package/dist/recording/otel/mappers.d.ts.map +0 -1
- package/dist/recording/otel/mappers.js +0 -683
- package/dist/recording/otel/mappers.js.map +0 -1
- package/dist/recording/otel/otel-emitter.d.ts +0 -43
- package/dist/recording/otel/otel-emitter.d.ts.map +0 -1
- package/dist/recording/otel/otel-emitter.js +0 -99
- package/dist/recording/otel/otel-emitter.js.map +0 -1
- package/dist/recording/otel/redaction.d.ts +0 -47
- package/dist/recording/otel/redaction.d.ts.map +0 -1
- package/dist/recording/otel/redaction.js +0 -88
- package/dist/recording/otel/redaction.js.map +0 -1
- package/dist/recording/records.d.ts.map +0 -1
- package/dist/recording/records.js +0 -14
- package/dist/recording/records.js.map +0 -1
- package/dist/recording/transport/batcher.d.ts +0 -59
- package/dist/recording/transport/batcher.d.ts.map +0 -1
- package/dist/recording/transport/batcher.js +0 -234
- package/dist/recording/transport/batcher.js.map +0 -1
- package/dist/recording/transport/client.d.ts +0 -41
- package/dist/recording/transport/client.d.ts.map +0 -1
- package/dist/recording/transport/client.js +0 -69
- package/dist/recording/transport/client.js.map +0 -1
- package/dist/recording/transport/config.d.ts +0 -53
- package/dist/recording/transport/config.d.ts.map +0 -1
- package/dist/recording/transport/config.js +0 -41
- package/dist/recording/transport/config.js.map +0 -1
- package/dist/recording/transport/index.d.ts +0 -16
- package/dist/recording/transport/index.d.ts.map +0 -1
- package/dist/recording/transport/index.js +0 -12
- package/dist/recording/transport/index.js.map +0 -1
- package/dist/recording/transport/rows.d.ts +0 -88
- package/dist/recording/transport/rows.d.ts.map +0 -1
- package/dist/recording/transport/rows.js +0 -15
- package/dist/recording/transport/rows.js.map +0 -1
- package/dist/recording/wiring/emitter-factory.d.ts +0 -39
- package/dist/recording/wiring/emitter-factory.d.ts.map +0 -1
- package/dist/recording/wiring/emitter-factory.js +0 -62
- package/dist/recording/wiring/emitter-factory.js.map +0 -1
- package/dist/recording/wiring/identity.d.ts +0 -27
- package/dist/recording/wiring/identity.d.ts.map +0 -1
- package/dist/recording/wiring/identity.js.map +0 -1
- package/dist/recording/wiring/index.d.ts +0 -12
- package/dist/recording/wiring/index.d.ts.map +0 -1
- package/dist/recording/wiring/index.js +0 -9
- package/dist/recording/wiring/index.js.map +0 -1
- package/dist/recording/wiring/record-builders.d.ts +0 -107
- package/dist/recording/wiring/record-builders.d.ts.map +0 -1
- package/dist/recording/wiring/record-builders.js.map +0 -1
- package/dist/recording/wiring/subscriber.d.ts +0 -28
- package/dist/recording/wiring/subscriber.d.ts.map +0 -1
- package/dist/recording/wiring/subscriber.js +0 -173
- package/dist/recording/wiring/subscriber.js.map +0 -1
- package/dist/recording/wiring/values.d.ts +0 -19
- package/dist/recording/wiring/values.d.ts.map +0 -1
- package/dist/recording/wiring/values.js +0 -49
- package/dist/recording/wiring/values.js.map +0 -1
- package/dist/tracking/build-rehydrate-items.d.ts +0 -15
- package/dist/tracking/build-rehydrate-items.d.ts.map +0 -1
- package/dist/tracking/build-rehydrate-items.js +0 -19
- package/dist/tracking/build-rehydrate-items.js.map +0 -1
- package/dist/tracking/constants.d.ts +0 -24
- package/dist/tracking/constants.d.ts.map +0 -1
- package/dist/tracking/constants.js +0 -52
- package/dist/tracking/constants.js.map +0 -1
- package/dist/tracking/context.d.ts.map +0 -1
- package/dist/tracking/context.js.map +0 -1
- package/dist/tracking/index.d.ts +0 -16
- package/dist/tracking/index.d.ts.map +0 -1
- package/dist/tracking/index.js +0 -11
- package/dist/tracking/index.js.map +0 -1
- package/dist/tracking/plugin-event-tracker.d.ts +0 -13
- package/dist/tracking/plugin-event-tracker.d.ts.map +0 -1
- package/dist/tracking/plugin-event-tracker.js +0 -27
- package/dist/tracking/plugin-event-tracker.js.map +0 -1
- package/dist/tracking/position-id-registry.d.ts.map +0 -1
- package/dist/tracking/position-id-registry.js.map +0 -1
- package/dist/tracking/spans/constants.d.ts +0 -19
- package/dist/tracking/spans/constants.d.ts.map +0 -1
- package/dist/tracking/spans/constants.js +0 -31
- package/dist/tracking/spans/constants.js.map +0 -1
- package/dist/tracking/spans/fan-out-span-transport.d.ts +0 -22
- package/dist/tracking/spans/fan-out-span-transport.d.ts.map +0 -1
- package/dist/tracking/spans/fan-out-span-transport.js +0 -49
- package/dist/tracking/spans/fan-out-span-transport.js.map +0 -1
- package/dist/tracking/spans/index.d.ts +0 -13
- package/dist/tracking/spans/index.d.ts.map +0 -1
- package/dist/tracking/spans/index.js +0 -16
- package/dist/tracking/spans/index.js.map +0 -1
- package/dist/tracking/spans/otel/fit-row-budget.d.ts +0 -22
- package/dist/tracking/spans/otel/fit-row-budget.d.ts.map +0 -1
- package/dist/tracking/spans/otel/fit-row-budget.js +0 -91
- package/dist/tracking/spans/otel/fit-row-budget.js.map +0 -1
- package/dist/tracking/spans/otel/map-span-to-trace-row.d.ts +0 -16
- package/dist/tracking/spans/otel/map-span-to-trace-row.d.ts.map +0 -1
- package/dist/tracking/spans/otel/map-span-to-trace-row.js +0 -227
- package/dist/tracking/spans/otel/map-span-to-trace-row.js.map +0 -1
- package/dist/tracking/spans/otel/recording-span-transport.d.ts +0 -43
- package/dist/tracking/spans/otel/recording-span-transport.d.ts.map +0 -1
- package/dist/tracking/spans/otel/recording-span-transport.js +0 -67
- package/dist/tracking/spans/otel/recording-span-transport.js.map +0 -1
- package/dist/tracking/spans/otel/span-ids.d.ts +0 -22
- package/dist/tracking/spans/otel/span-ids.d.ts.map +0 -1
- package/dist/tracking/spans/otel/span-ids.js +0 -32
- package/dist/tracking/spans/otel/span-ids.js.map +0 -1
- package/dist/tracking/spans/plugin-span-tracker.d.ts +0 -9
- package/dist/tracking/spans/plugin-span-tracker.d.ts.map +0 -1
- package/dist/tracking/spans/plugin-span-tracker.js +0 -115
- package/dist/tracking/spans/plugin-span-tracker.js.map +0 -1
- package/dist/tracking/spans/redact-pii.d.ts.map +0 -1
- package/dist/tracking/spans/redact-pii.js.map +0 -1
- package/dist/tracking/spans/sanitize-payload.d.ts.map +0 -1
- package/dist/tracking/spans/sanitize-payload.js.map +0 -1
- package/dist/tracking/spans/span-hooks.d.ts +0 -28
- package/dist/tracking/spans/span-hooks.d.ts.map +0 -1
- package/dist/tracking/spans/span-hooks.js +0 -409
- package/dist/tracking/spans/span-hooks.js.map +0 -1
- package/dist/tracking/spans/span-tracker.d.ts +0 -133
- package/dist/tracking/spans/span-tracker.d.ts.map +0 -1
- package/dist/tracking/spans/span-tracker.js +0 -721
- package/dist/tracking/spans/span-tracker.js.map +0 -1
- package/dist/tracking/spans/span-transport.d.ts +0 -71
- package/dist/tracking/spans/span-transport.d.ts.map +0 -1
- package/dist/tracking/spans/span-transport.js +0 -240
- package/dist/tracking/spans/span-transport.js.map +0 -1
- package/dist/tracking/spans/types.d.ts +0 -101
- package/dist/tracking/spans/types.d.ts.map +0 -1
- package/dist/tracking/spans/types.js +0 -6
- package/dist/tracking/spans/types.js.map +0 -1
- package/dist/tracking/tracker.d.ts +0 -30
- package/dist/tracking/tracker.d.ts.map +0 -1
- package/dist/tracking/tracker.js +0 -66
- package/dist/tracking/tracker.js.map +0 -1
- package/dist/tracking/tracking-handler.d.ts +0 -12
- package/dist/tracking/tracking-handler.d.ts.map +0 -1
- package/dist/tracking/tracking-handler.js +0 -148
- package/dist/tracking/tracking-handler.js.map +0 -1
- package/dist/tracking/transport.d.ts +0 -35
- package/dist/tracking/transport.d.ts.map +0 -1
- package/dist/tracking/transport.js +0 -133
- package/dist/tracking/transport.js.map +0 -1
- package/dist/tracking/types.d.ts +0 -21
- package/dist/tracking/types.d.ts.map +0 -1
- package/dist/tracking/types.js +0 -6
- package/dist/tracking/types.js.map +0 -1
- /package/dist/{tracking → telemetry}/spans/sanitize-payload.d.ts +0 -0
- /package/dist/{tracking → telemetry}/spans/sanitize-payload.js +0 -0
package/dist/runtime/runtime.js
CHANGED
|
@@ -12,6 +12,7 @@ import { createRiskGuard, createRiskGuardStub } from "./risk-guard.js";
|
|
|
12
12
|
import { createStrategyLifecycle } from "./strategy-lifecycle.js";
|
|
13
13
|
// RiskGuardianService removed — gate decisions are now real-time in checkGate
|
|
14
14
|
import { createRiskAuditLog } from "../risk/risk-audit-log.js";
|
|
15
|
+
import { createEventStore, registerEventSink, unregisterEventSink, flushEventSink } from "../telemetry/event-store.js";
|
|
15
16
|
import { createNotificationService } from "./notifications.js";
|
|
16
17
|
import { resolveStrategyConfig } from "./map-strategies.js";
|
|
17
18
|
import { mapRuntimeExitToDslConfig } from "./map-exit-config.js";
|
|
@@ -31,16 +32,32 @@ import { createActionNotificationSubscriber, isActionLifecycleNotificationsEnabl
|
|
|
31
32
|
import { MaxLeverageCache } from "../leverage/max-leverage-cache.js";
|
|
32
33
|
import { buildStateLayout } from "./state-layout.js";
|
|
33
34
|
import { createLogger } from "../utils/logger.js";
|
|
34
|
-
import {
|
|
35
|
+
import { buildScannerSummaryEvent, buildRuntimeStartedEvent, buildRuntimeStoppedEvent, buildRuntimeErrorEvent, buildQueueBackpressureEvent, } from "./lifecycle-events.js";
|
|
36
|
+
import { emitEvent } from "../actions/event-derivation.js";
|
|
37
|
+
import { createDomainEventSubscriber } from "./domain-events.js";
|
|
38
|
+
import { PositionIdRegistry, buildRehydrateItems, } from "./position-id-registry.js";
|
|
35
39
|
import { VERSION } from "../version.js";
|
|
36
40
|
import { randomUUID } from "node:crypto";
|
|
37
|
-
import { trackingContext } from "../
|
|
38
|
-
import { buildIdentity,
|
|
41
|
+
import { trackingContext } from "../telemetry/context.js";
|
|
42
|
+
import { buildIdentity, } from "../telemetry/identity.js";
|
|
39
43
|
import { runReconcile } from "./reconcile-run.js";
|
|
40
44
|
import { KeyedMutex } from "../utils/keyed-mutex.js";
|
|
45
|
+
import { withSpan } from "../telemetry/tracing.js";
|
|
46
|
+
import { registerDslActivePositionsGauge, registerQueueDepthGauge, recordScannerRun, recordSignalQueueWait, recordRuntimeHeartbeat, } from "../telemetry/metrics.js";
|
|
47
|
+
import { isOtlpEndpointConfigured } from "../telemetry/otel-sdk.js";
|
|
48
|
+
import { identityTraceAttributes, setTraceIdentityAttributes, } from "../telemetry/trace-identity.js";
|
|
41
49
|
const logger = createLogger("[senpi-core][runtime]");
|
|
42
50
|
/** Fixed retry interval for the boot-reconcile loop. */
|
|
43
51
|
const RECONCILE_RETRY_INTERVAL_MS = 15_000;
|
|
52
|
+
/**
|
|
53
|
+
* Signal-queue depth at which the serial consumer is judged to be falling behind. It processes one
|
|
54
|
+
* signal at a time (each may run an LLM decision), so a backlog this deep means inflow is outpacing
|
|
55
|
+
* processing — a `runtime.queue_backpressure` alert. Hardcoded: the depth a stall shows at is a
|
|
56
|
+
* runtime invariant, not a per-recipe tuning knob.
|
|
57
|
+
*/
|
|
58
|
+
const SIGNAL_QUEUE_BACKPRESSURE_THRESHOLD = 10;
|
|
59
|
+
/** Default liveness-heartbeat window (~15 min) when `health.window_seconds` is unset. */
|
|
60
|
+
const DEFAULT_LIVENESS_WINDOW_SECONDS = 900;
|
|
44
61
|
export class Runtime {
|
|
45
62
|
config;
|
|
46
63
|
options;
|
|
@@ -53,9 +70,13 @@ export class Runtime {
|
|
|
53
70
|
// riskGuardian removed — gate decisions are now real-time in checkGate
|
|
54
71
|
senpi = null;
|
|
55
72
|
healthStateModule = null;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
73
|
+
domainEventSubscriber = null;
|
|
74
|
+
/** Wallet under which this runtime's local event sink is registered; cleared on teardown. */
|
|
75
|
+
eventSinkAddress = null;
|
|
76
|
+
/** Lazy runtime identity builder; stamps per-trace identity at the signal.process seam. */
|
|
77
|
+
buildTraceIdentity;
|
|
78
|
+
traceIdentity;
|
|
79
|
+
traceIdentityResolved = false;
|
|
59
80
|
started = false;
|
|
60
81
|
startedAt = null;
|
|
61
82
|
/** Serial signal processing: queue and consumer so only one signal is handled at a time. */
|
|
@@ -63,13 +84,17 @@ export class Runtime {
|
|
|
63
84
|
signalQueueWait = null;
|
|
64
85
|
signalConsumerStopped = false;
|
|
65
86
|
signalConsumerDone = null;
|
|
87
|
+
/** Disposer for this runtime's `runtime.queue_depth` gauge observation; set on start, called on stop. */
|
|
88
|
+
queueDepthGaugeDispose = null;
|
|
89
|
+
/** Disposer for this runtime's `dsl.active_positions` gauge observation; set on start, called on stop. */
|
|
90
|
+
dslActivePositionsGaugeDispose = null;
|
|
91
|
+
/** Interval emitting this runtime's liveness heartbeat; set on start, cleared on stop. */
|
|
92
|
+
livenessHeartbeatTimer = null;
|
|
66
93
|
runActionsForSignal;
|
|
67
94
|
strategyConfig;
|
|
68
95
|
actionRuntimeModule;
|
|
69
96
|
/** Stored so we can call off() in stop() and avoid retaining Runtime via scanner EventEmitter. */
|
|
70
97
|
onScannerRunComplete = null;
|
|
71
|
-
onScannerRunSkip = null;
|
|
72
|
-
onScannerRunError = null;
|
|
73
98
|
/** Cached strategy id resolved from the runtime wallet on first {@link auditQuery} call. */
|
|
74
99
|
cachedStrategyId = null;
|
|
75
100
|
/** In-flight resolution promise; ensures concurrent first-burst callers reuse one `listStrategies`. */
|
|
@@ -137,20 +162,7 @@ export class Runtime {
|
|
|
137
162
|
if (!this.started) {
|
|
138
163
|
throw new Error("Runtime must be started before accepting external scanner ingests.");
|
|
139
164
|
}
|
|
140
|
-
console.info("[senpi-runtime] [ingest-trace] runtime.ingestExternalScannerData", JSON.stringify({
|
|
141
|
-
address: this.strategyConfig.address,
|
|
142
|
-
scanner: request.scanner,
|
|
143
|
-
hasAsset: request.asset !== undefined,
|
|
144
|
-
hasData: request.data !== undefined,
|
|
145
|
-
hasSignals: request.signals !== undefined,
|
|
146
|
-
dataKeys: request.data ? Object.keys(request.data) : [],
|
|
147
|
-
}));
|
|
148
165
|
const result = await this.scannerModule.ingestExternalScannerData(this.strategyConfig.address, request);
|
|
149
|
-
console.info("[senpi-runtime] [ingest-trace] runtime.ingestExternalScannerData → done", JSON.stringify({
|
|
150
|
-
accepted: result.accepted,
|
|
151
|
-
signalCount: result.signalCount,
|
|
152
|
-
contextUpdated: result.contextUpdated,
|
|
153
|
-
}));
|
|
154
166
|
return result;
|
|
155
167
|
}
|
|
156
168
|
/**
|
|
@@ -309,18 +321,6 @@ export class Runtime {
|
|
|
309
321
|
validateDslPositionTracking(this.config, hasDsl);
|
|
310
322
|
this.bus = createRuntimeBus();
|
|
311
323
|
this.hookSystem = createHookSystem(this.bus);
|
|
312
|
-
// Event tracking: passive bus → EventTracker → BatchingTransport POST (requires JWT-capable API key).
|
|
313
|
-
// Without SENPI_API_KEY, NoOpTransport discards all events; warn once at startup.
|
|
314
|
-
const trackingApiKey = apiKey ?? process.env.SENPI_AUTH_TOKEN ?? process.env.SENPI_API_KEY;
|
|
315
|
-
const trackingBaseUrl = process.env.SENPI_TRACKING_URL ?? TRACKING_API_BASE_URL;
|
|
316
|
-
const trackingTransport = trackingApiKey
|
|
317
|
-
? new BatchingTransport({ baseUrl: trackingBaseUrl, apiKey: trackingApiKey })
|
|
318
|
-
: (() => {
|
|
319
|
-
logger.warn("event tracking disabled: set SENPI_API_KEY (or pass apiKey) so events reach senpi-agent-telemetry; without it NoOpTransport drops all telemetry");
|
|
320
|
-
return new NoOpTransport();
|
|
321
|
-
})();
|
|
322
|
-
const tracker = new EventTracker(trackingTransport, this.config.name, VERSION, this.config.strategy?.wallet ?? "");
|
|
323
|
-
this.trackingHandler = createTrackingHandler(this.bus, tracker);
|
|
324
324
|
this.stateManager = new StateManager(stateDir);
|
|
325
325
|
await this.stateManager.hydrate();
|
|
326
326
|
this.positionIdRegistry = new PositionIdRegistry();
|
|
@@ -344,41 +344,29 @@ export class Runtime {
|
|
|
344
344
|
this.senpi = senpi;
|
|
345
345
|
this.strategyConfig = resolveStrategyConfig(this.config);
|
|
346
346
|
await this.rehydratePositionIdRegistry();
|
|
347
|
-
//
|
|
348
|
-
//
|
|
349
|
-
|
|
350
|
-
//
|
|
351
|
-
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
bootId: this.runtimeBootId,
|
|
360
|
-
unresolvedConfig: this.options.unresolvedConfig,
|
|
361
|
-
}),
|
|
362
|
-
scopeVersion: VERSION,
|
|
363
|
-
baseUrl: telemetryConfig?.url,
|
|
364
|
-
// v2.0.0: recipe carries flush_interval_seconds; the transport expects ms.
|
|
365
|
-
flushIntervalMs: typeof telemetryConfig?.flush_interval_seconds === "number"
|
|
366
|
-
? telemetryConfig.flush_interval_seconds * 1000
|
|
367
|
-
: undefined,
|
|
347
|
+
// The OTLP exporter env is the telemetry master switch: the OTel SDK (stood up at plugin
|
|
348
|
+
// register()) and the domain-event log both gate on it.
|
|
349
|
+
const telemetryEnabled = isOtlpEndpointConfigured();
|
|
350
|
+
// Lazy identity builder. Built only on the live path (never from the resolved
|
|
351
|
+
// config, which would inline secrets).
|
|
352
|
+
const buildIdentityEnvelope = () => buildIdentity({
|
|
353
|
+
name: this.config.name,
|
|
354
|
+
recipeVersion: this.config.version,
|
|
355
|
+
strategyAddress: this.strategyConfig.address,
|
|
356
|
+
group: this.config.group,
|
|
357
|
+
bootId: this.runtimeBootId,
|
|
358
|
+
unresolvedConfig: this.options.unresolvedConfig,
|
|
368
359
|
});
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
//
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
// registry or RuntimeContext; sync map read, safe on the bus handler path.
|
|
377
|
-
resolvePositionId: (address, dex, asset) => this.positionIdRegistry.get(positionRegistryKey(address, dex, asset))?.positionId,
|
|
378
|
-
});
|
|
360
|
+
// Share the builder with the signal.process root span (resolved lazily, once per boot).
|
|
361
|
+
this.buildTraceIdentity = buildIdentityEnvelope;
|
|
362
|
+
// The event-log half of the real domain events (position.*/dsl.*) → OTel Logs API. Rides the
|
|
363
|
+
// OTel SDK's log provider. Per-event assembly on the serial signal path is dead work when
|
|
364
|
+
// telemetry is off, so only attach when enabled.
|
|
365
|
+
if (telemetryEnabled) {
|
|
366
|
+
this.domainEventSubscriber = createDomainEventSubscriber(this.bus);
|
|
379
367
|
}
|
|
380
368
|
// Everything from here to `started = true` can throw; without the catch, stop() would
|
|
381
|
-
// early-return on `!this.started` and the
|
|
369
|
+
// early-return on `!this.started` and the domain-event subscriber would leak.
|
|
382
370
|
try {
|
|
383
371
|
// try {
|
|
384
372
|
// const { reconcileStateWithBackend } = await import("./reconcile-state.js");
|
|
@@ -395,6 +383,10 @@ export class Runtime {
|
|
|
395
383
|
const riskBlock = this.config.risk;
|
|
396
384
|
const strategyAddress = this.strategyConfig.address;
|
|
397
385
|
const auditLog = riskBlock ? createRiskAuditLog(stateDir) : undefined;
|
|
386
|
+
// Local domain-event ring. Always on (independent of the OTLP collector) so the agent can query
|
|
387
|
+
// the trade narrative locally; the singleton logger taps it by wallet via this registration.
|
|
388
|
+
registerEventSink(strategyAddress, createEventStore(stateDir, strategyAddress));
|
|
389
|
+
this.eventSinkAddress = strategyAddress;
|
|
398
390
|
// In-memory strategy-lifecycle tracker: owns the self-pause state that
|
|
399
391
|
// RiskGuard used to hold and fires the hook + notification on a running→paused
|
|
400
392
|
// transition. RiskGuard stays stateless and only reports gate evaluations.
|
|
@@ -423,7 +415,7 @@ export class Runtime {
|
|
|
423
415
|
getDslStatesForStrategy: scannerProviders?.getDslStatesForStrategy
|
|
424
416
|
?? (async (address) => this.stateManager.listDslStates(address)),
|
|
425
417
|
};
|
|
426
|
-
this.scannerModule = createScannerModuleFromRuntimeConfig(this.config, layout.scannerRoot, augmentedProviders);
|
|
418
|
+
this.scannerModule = createScannerModuleFromRuntimeConfig(this.config, layout.scannerRoot, augmentedProviders, undefined, buildIdentityEnvelope);
|
|
427
419
|
logger.info("Runtime.start() scanner module created, calling start()");
|
|
428
420
|
// Pre-load max leverage cache (non-blocking — log warning on failure)
|
|
429
421
|
const maxLeverageCache = new MaxLeverageCache(senpi);
|
|
@@ -493,6 +485,7 @@ export class Runtime {
|
|
|
493
485
|
// against the trade loop on the same reconcileMutex key, and can resolve the boot gate.
|
|
494
486
|
reconcileSerialize: (fn) => this.reconcileMutex.withKeyLock("reconcile", fn),
|
|
495
487
|
reconcileGateResolve: () => this.resolveReconcileGate(),
|
|
488
|
+
identity: buildIdentityEnvelope,
|
|
496
489
|
});
|
|
497
490
|
}
|
|
498
491
|
else {
|
|
@@ -529,34 +522,40 @@ export class Runtime {
|
|
|
529
522
|
},
|
|
530
523
|
});
|
|
531
524
|
this.onScannerRunComplete = (event) => {
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
525
|
+
// Per-scan-run id: stamped on the scanner_run emit and echoed through the pass so scan +
|
|
526
|
+
// pass land in one trace. Prefer the id minted at the scanner.run span so scan + pass
|
|
527
|
+
// share one senpi.run.id.
|
|
528
|
+
const runId = event.result.runId ?? randomUUID();
|
|
529
|
+
this.signalQueue.push({ result: event.result, enqueuedAt: Date.now(), runId });
|
|
530
|
+
// Edge-triggered backpressure alarm: depth rises one enqueue at a time, so `=== threshold`
|
|
531
|
+
// fires exactly once as it crosses up and re-arms only after the consumer drains back below.
|
|
532
|
+
if (this.signalQueue.length === SIGNAL_QUEUE_BACKPRESSURE_THRESHOLD) {
|
|
533
|
+
emitEvent(logger, () => buildQueueBackpressureEvent({
|
|
534
|
+
depth: this.signalQueue.length,
|
|
535
|
+
threshold: SIGNAL_QUEUE_BACKPRESSURE_THRESHOLD,
|
|
536
|
+
scannerId: event.result.scannerId,
|
|
537
|
+
address: this.strategyConfig.address,
|
|
538
|
+
}));
|
|
539
|
+
}
|
|
544
540
|
if (this.signalQueueWait) {
|
|
545
541
|
const w = this.signalQueueWait;
|
|
546
542
|
this.signalQueueWait = null;
|
|
547
543
|
w();
|
|
548
544
|
}
|
|
549
|
-
//
|
|
550
|
-
|
|
545
|
+
// Scanner-run summary payload (startedAt is data stamping for telemetry durations).
|
|
546
|
+
const scannerRunPayload = {
|
|
551
547
|
address: event.result.address,
|
|
552
548
|
data: {
|
|
553
549
|
...event.result,
|
|
554
550
|
startedAt: event.startedAt,
|
|
555
551
|
runId,
|
|
556
|
-
__correlationId: correlationId,
|
|
557
552
|
},
|
|
558
553
|
timestamp: new Date().toISOString(),
|
|
559
|
-
}
|
|
554
|
+
};
|
|
555
|
+
// First-class event log. The build runs inside emitEvent's guard — telemetry never
|
|
556
|
+
// disturbs the scan path.
|
|
557
|
+
emitEvent(logger, () => buildScannerSummaryEvent(scannerRunPayload, Date.now()));
|
|
558
|
+
recordScannerRun({ scannerId: event.result.scannerId, outcome: event.result.status });
|
|
560
559
|
// Forward scanner summary alerts (e.g. watchdog) to notification service
|
|
561
560
|
const alerts = event.result.summary?.alerts;
|
|
562
561
|
if (Array.isArray(alerts) && alerts.length > 0) {
|
|
@@ -566,37 +565,6 @@ export class Runtime {
|
|
|
566
565
|
}
|
|
567
566
|
};
|
|
568
567
|
this.scannerModule.on("scanner:run:complete", this.onScannerRunComplete);
|
|
569
|
-
// Surface skipped/errored scanner runs on the bus for telemetry (add-only observation events —
|
|
570
|
-
// distinct names so existing `tracking.scanner_run` consumers see an unchanged payload mix).
|
|
571
|
-
// Neither enqueues a signal: only completed runs feed the signal queue.
|
|
572
|
-
this.onScannerRunSkip = (event) => {
|
|
573
|
-
this.bus.emit("tracking.scanner_run_skipped", {
|
|
574
|
-
address: event.address,
|
|
575
|
-
data: {
|
|
576
|
-
scannerId: event.scannerId,
|
|
577
|
-
status: event.status,
|
|
578
|
-
reason: event.reason,
|
|
579
|
-
timestamp: event.timestamp,
|
|
580
|
-
startedAt: event.startedAt,
|
|
581
|
-
},
|
|
582
|
-
timestamp: new Date().toISOString(),
|
|
583
|
-
});
|
|
584
|
-
};
|
|
585
|
-
this.onScannerRunError = (event) => {
|
|
586
|
-
this.bus.emit("tracking.scanner_run_error", {
|
|
587
|
-
address: event.address,
|
|
588
|
-
data: {
|
|
589
|
-
scannerId: event.scannerId,
|
|
590
|
-
status: "error",
|
|
591
|
-
reason: typeof event.error === "string" ? event.error : String(event.error),
|
|
592
|
-
timestamp: event.timestamp,
|
|
593
|
-
startedAt: event.startedAt,
|
|
594
|
-
},
|
|
595
|
-
timestamp: new Date().toISOString(),
|
|
596
|
-
});
|
|
597
|
-
};
|
|
598
|
-
this.scannerModule.on("scanner:run:skip", this.onScannerRunSkip);
|
|
599
|
-
this.scannerModule.on("scanner:run:error", this.onScannerRunError);
|
|
600
568
|
this.signalConsumerDone = this.runSignalConsumer();
|
|
601
569
|
logger.info("Runtime.start() invoking scannerModule.start()");
|
|
602
570
|
await this.scannerModule.start();
|
|
@@ -640,14 +608,6 @@ export class Runtime {
|
|
|
640
608
|
this.scannerModule.off("scanner:run:complete", this.onScannerRunComplete);
|
|
641
609
|
this.onScannerRunComplete = null;
|
|
642
610
|
}
|
|
643
|
-
if (this.onScannerRunSkip != null) {
|
|
644
|
-
this.scannerModule.off("scanner:run:skip", this.onScannerRunSkip);
|
|
645
|
-
this.onScannerRunSkip = null;
|
|
646
|
-
}
|
|
647
|
-
if (this.onScannerRunError != null) {
|
|
648
|
-
this.scannerModule.off("scanner:run:error", this.onScannerRunError);
|
|
649
|
-
this.onScannerRunError = null;
|
|
650
|
-
}
|
|
651
611
|
if (this.actionNotificationSubscriber != null) {
|
|
652
612
|
this.actionNotificationSubscriber.dispose();
|
|
653
613
|
this.actionNotificationSubscriber = null;
|
|
@@ -664,22 +624,66 @@ export class Runtime {
|
|
|
664
624
|
catch (cleanupErr) {
|
|
665
625
|
logger.warn("[runtime] partial-state cleanup error on failed start (ignored)", { cleanupErr });
|
|
666
626
|
}
|
|
667
|
-
//
|
|
668
|
-
await this.
|
|
627
|
+
// Telemetry cleanup (must not leak on a failed boot); the error rethrows.
|
|
628
|
+
await this.disposeSubscribers();
|
|
669
629
|
throw err;
|
|
670
630
|
}
|
|
671
|
-
|
|
631
|
+
// First-class event log. Carries the UNRESOLVED config hash (the form `computeConfigHash` uses),
|
|
632
|
+
// so the printed hash matches `senpi.config.hash` on the spans/logs. The build runs inside
|
|
633
|
+
// emitEvent's guard — telemetry never blocks boot.
|
|
634
|
+
emitEvent(logger, () => buildRuntimeStartedEvent({
|
|
672
635
|
address: this.strategyConfig.address,
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
636
|
+
recipeName: this.config.name,
|
|
637
|
+
recipeVersion: this.config.version,
|
|
638
|
+
runtimeVersion: VERSION,
|
|
639
|
+
scannerCount: this.config.scanners?.length ?? 0,
|
|
640
|
+
actionCount: this.config.actions?.length ?? 0,
|
|
641
|
+
hasDsl: this.dslPlugin != null,
|
|
642
|
+
unresolvedConfig: this.options.unresolvedConfig,
|
|
643
|
+
slots: this.strategyConfig.slots,
|
|
644
|
+
tradingRisk: this.strategyConfig.tradingRisk,
|
|
645
|
+
marginPerSlot: this.strategyConfig.marginPerSlot,
|
|
646
|
+
marginPct: this.strategyConfig.marginPct,
|
|
647
|
+
defaultLeverage: this.strategyConfig.defaultLeverage,
|
|
648
|
+
}));
|
|
649
|
+
// Observable gauge of the serial signal-queue depth — its absence/stall is alertable without a
|
|
650
|
+
// trace or log scan. Reads the live depth at each collection; disposed in stop().
|
|
651
|
+
const walletDim = this.strategyConfig.address.toLowerCase();
|
|
652
|
+
const group = this.config.group;
|
|
653
|
+
this.queueDepthGaugeDispose = registerQueueDepthGauge({
|
|
654
|
+
strategyAddress: walletDim,
|
|
655
|
+
group,
|
|
656
|
+
read: () => this.getSignalQueueDepth(),
|
|
682
657
|
});
|
|
658
|
+
// Liveness heartbeat: a positive tick every window, dimensioned by wallet/group. A dead runtime
|
|
659
|
+
// can't emit a "down" event — only the absence of these ticks detects it. Fire one now so a
|
|
660
|
+
// runtime that dies before its first window still leaves a mark. Unref'd so it never holds the
|
|
661
|
+
// process open; cleared in stop().
|
|
662
|
+
const windowSec = this.config.health?.window_seconds ?? DEFAULT_LIVENESS_WINDOW_SECONDS;
|
|
663
|
+
recordRuntimeHeartbeat({ strategyAddress: walletDim, group });
|
|
664
|
+
this.livenessHeartbeatTimer = setInterval(() => recordRuntimeHeartbeat({ strategyAddress: walletDim, group }), windowSec * 1000);
|
|
665
|
+
this.livenessHeartbeatTimer.unref?.();
|
|
666
|
+
// Observable gauge of active DSL-managed positions, split by exit phase. Only meaningful when this
|
|
667
|
+
// runtime runs the exit engine; counts this wallet's positions live at each collection (no snapshot).
|
|
668
|
+
if (this.dslPlugin) {
|
|
669
|
+
this.dslActivePositionsGaugeDispose = registerDslActivePositionsGauge({
|
|
670
|
+
strategyAddress: walletDim,
|
|
671
|
+
group,
|
|
672
|
+
read: () => {
|
|
673
|
+
let phase1 = 0;
|
|
674
|
+
let phase2 = 0;
|
|
675
|
+
for (const p of this.dslPlugin?.listActivePositions() ?? []) {
|
|
676
|
+
if (p.address?.toLowerCase() !== walletDim)
|
|
677
|
+
continue;
|
|
678
|
+
if (p.phase === 2)
|
|
679
|
+
phase2++;
|
|
680
|
+
else
|
|
681
|
+
phase1++;
|
|
682
|
+
}
|
|
683
|
+
return { phase1, phase2 };
|
|
684
|
+
},
|
|
685
|
+
});
|
|
686
|
+
}
|
|
683
687
|
}
|
|
684
688
|
/**
|
|
685
689
|
* Cancel exchange SLs and archive DSL state for the strategy, then log removal.
|
|
@@ -695,7 +699,24 @@ export class Runtime {
|
|
|
695
699
|
}
|
|
696
700
|
/** Tear down DSL for the runtime strategy before deleting the runtime (gateway / CLI). */
|
|
697
701
|
async teardownDslForRuntimeDeletion() {
|
|
698
|
-
|
|
702
|
+
await this.removeStrategy(this.strategyConfig.address);
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Resolve the per-boot trace identity once. The envelope is immutable per boot, so build it
|
|
706
|
+
* lazily and cache it. The build is guarded: a failing identity builder must never abort
|
|
707
|
+
* signal processing.
|
|
708
|
+
*/
|
|
709
|
+
resolveTraceIdentity() {
|
|
710
|
+
if (!this.traceIdentityResolved) {
|
|
711
|
+
this.traceIdentityResolved = true;
|
|
712
|
+
try {
|
|
713
|
+
this.traceIdentity = this.buildTraceIdentity?.();
|
|
714
|
+
}
|
|
715
|
+
catch (err) {
|
|
716
|
+
logger.warn("[runtime] failed to build trace identity; continuing without it", { err });
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
return this.traceIdentity;
|
|
699
720
|
}
|
|
700
721
|
/**
|
|
701
722
|
* Single consumer: process one scanner:run:complete at a time so slot counts stay correct.
|
|
@@ -714,84 +735,113 @@ export class Runtime {
|
|
|
714
735
|
if (!item)
|
|
715
736
|
continue;
|
|
716
737
|
// Pin tracking context for this signal flow so LLM spans (emitted by
|
|
717
|
-
// OpenClawLlmDecision / AnthropicLlmDecision) can stamp
|
|
738
|
+
// OpenClawLlmDecision / AnthropicLlmDecision) can stamp run id,
|
|
718
739
|
// address, recipe_name, runtime_id, and runtime_version automatically.
|
|
719
740
|
const queuedItem = item;
|
|
741
|
+
// Resolved once here so the same identity rides both the trace (via the span stamp)
|
|
742
|
+
// and the logs (via the context bag below) — one source, no drift.
|
|
743
|
+
const identity = this.resolveTraceIdentity();
|
|
720
744
|
await trackingContext.run({
|
|
721
|
-
|
|
745
|
+
runId: queuedItem.runId,
|
|
722
746
|
address: queuedItem.result.address,
|
|
723
747
|
recipeName: this.config.name,
|
|
724
748
|
runtimeId: this.options.runtimeId ?? "",
|
|
725
749
|
runtimeVersion: VERSION,
|
|
726
750
|
runtimeBootId: this.runtimeBootId,
|
|
751
|
+
identityAttributes: identity
|
|
752
|
+
? identityTraceAttributes(identity)
|
|
753
|
+
: undefined,
|
|
727
754
|
}, async () => {
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
return;
|
|
737
|
-
}
|
|
738
|
-
// Evict the blackout backlog. Items enqueued before the gate
|
|
739
|
-
// resolved were formed while the runtime could not confirm its own
|
|
740
|
-
// positions (unreconciled / exchange-flaky), so acting on them now is
|
|
741
|
-
// stale — the scanner re-emits fresh signals once reconciled. Strict
|
|
742
|
-
// `<`: items enqueued at/after gate-open are processed normally. This
|
|
743
|
-
// is gate-scoped, NOT a queue TTL — nothing is evicted once the
|
|
744
|
-
// backlog is cleared.
|
|
745
|
-
if (this.gateResolvedAt != null && queuedItem.enqueuedAt < this.gateResolvedAt) {
|
|
746
|
-
this.staleSignalsEvicted++;
|
|
747
|
-
logger.warn("[runtime] evicting stale pre-reconcile signal (enqueued before gate open)", {
|
|
748
|
-
address: queuedItem.result.address,
|
|
749
|
-
scannerId: queuedItem.result.scannerId,
|
|
750
|
-
enqueuedAt: queuedItem.enqueuedAt,
|
|
751
|
-
gateResolvedAt: this.gateResolvedAt,
|
|
752
|
-
totalEvicted: this.staleSignalsEvicted,
|
|
753
|
-
});
|
|
754
|
-
return;
|
|
755
|
-
}
|
|
756
|
-
console.info("[senpi-runtime] [ingest-trace] consumer dequeue → runActionsForSignal", JSON.stringify({
|
|
757
|
-
address: queuedItem.result.address,
|
|
758
|
-
scannerId: queuedItem.result.scannerId,
|
|
759
|
-
signalCount: Array.isArray(queuedItem.result.signals) ? queuedItem.result.signals.length : 0,
|
|
760
|
-
queueRemaining: this.signalQueue.length,
|
|
761
|
-
}));
|
|
762
|
-
const usedSlotsByStrategy = await this.stateManager.getUsedSlotsByStrategy([this.strategyConfig.address]);
|
|
763
|
-
const payload = buildActionScanPayload(queuedItem.result, this.strategyConfig, {
|
|
764
|
-
usedSlotsByStrategy,
|
|
765
|
-
address: queuedItem.result.address,
|
|
766
|
-
});
|
|
767
|
-
const hookEvent = {
|
|
768
|
-
type: HOOK_EVENT.ON_SIGNAL_DETECTED,
|
|
769
|
-
runtimeName: this.config.name,
|
|
770
|
-
address: queuedItem.result.address,
|
|
771
|
-
data: {
|
|
772
|
-
...payload,
|
|
773
|
-
__correlationId: queuedItem.correlationId,
|
|
774
|
-
__scanRunId: queuedItem.runId,
|
|
775
|
-
},
|
|
776
|
-
timestamp: new Date().toISOString(),
|
|
777
|
-
};
|
|
778
|
-
this.bus.emit(HOOK_EVENT.ON_SIGNAL_DETECTED, hookEvent);
|
|
779
|
-
// Serialize trade loop vs reconcile — reconcileMutex outer, key-lock inner.
|
|
780
|
-
await this.reconcileMutex.withKeyLock("reconcile", () => this.runActionsForSignal(hookEvent));
|
|
781
|
-
console.info("[senpi-runtime] [ingest-trace] runActionsForSignal complete", JSON.stringify({ address: queuedItem.result.address, scannerId: queuedItem.result.scannerId }));
|
|
755
|
+
// Block until the first boot reconcile succeeds (or runtime is stopped).
|
|
756
|
+
await this.reconcileGate?.promise;
|
|
757
|
+
// If stop() resolved the gate during shutdown, do NOT trade and do NOT
|
|
758
|
+
// contend for reconcileMutex — a boot reconcile that is still in-flight
|
|
759
|
+
// (or stuck) holds that key, and blocking here would hang stop()'s
|
|
760
|
+
// `await signalConsumerDone`. Bail before the mutex acquire.
|
|
761
|
+
if (this.signalConsumerStopped) {
|
|
762
|
+
return;
|
|
782
763
|
}
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
764
|
+
// Evict the blackout backlog. Items enqueued before the gate
|
|
765
|
+
// resolved were formed while the runtime could not confirm its own
|
|
766
|
+
// positions (unreconciled / exchange-flaky), so acting on them now is
|
|
767
|
+
// stale — the scanner re-emits fresh signals once reconciled. Strict
|
|
768
|
+
// `<`: items enqueued at/after gate-open are processed normally. This
|
|
769
|
+
// is gate-scoped, NOT a queue TTL — nothing is evicted once the
|
|
770
|
+
// backlog is cleared.
|
|
771
|
+
if (this.gateResolvedAt != null && queuedItem.enqueuedAt < this.gateResolvedAt) {
|
|
772
|
+
this.staleSignalsEvicted++;
|
|
773
|
+
logger.warn("[runtime] evicting stale pre-reconcile signal (enqueued before gate open)", {
|
|
789
774
|
address: queuedItem.result.address,
|
|
790
775
|
scannerId: queuedItem.result.scannerId,
|
|
791
|
-
|
|
792
|
-
|
|
776
|
+
enqueuedAt: queuedItem.enqueuedAt,
|
|
777
|
+
gateResolvedAt: this.gateResolvedAt,
|
|
778
|
+
totalEvicted: this.staleSignalsEvicted,
|
|
793
779
|
});
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
// Root span born at dequeue; spans for the action handlers nest beneath it.
|
|
783
|
+
// Identity (incl. strategy address) rides every span via the per-trace stamp below;
|
|
784
|
+
// run.id is the join key back to the producing scanner run.
|
|
785
|
+
const spanAttrs = {};
|
|
786
|
+
if (queuedItem.runId) {
|
|
787
|
+
spanAttrs["senpi.run.id"] = queuedItem.runId;
|
|
788
|
+
}
|
|
789
|
+
// Carry the producing scanner id so the signal span joins/filters by scanner,
|
|
790
|
+
// matching the key the sibling scanner.run span stamps.
|
|
791
|
+
if (queuedItem.result.scannerId) {
|
|
792
|
+
spanAttrs["senpi.scanner.id"] = queuedItem.result.scannerId;
|
|
794
793
|
}
|
|
794
|
+
await withSpan("signal.process", spanAttrs, async (span) => {
|
|
795
|
+
if (identity)
|
|
796
|
+
await setTraceIdentityAttributes(identity);
|
|
797
|
+
// Serial FIFO: time spent waiting behind earlier signals, and the depth still
|
|
798
|
+
// behind this one — the backpressure a per-pass duration alone can't show.
|
|
799
|
+
// Measured from enqueue, but the pre-gate backlog is evicted above before the
|
|
800
|
+
// span opens, so every signal that reaches here was enqueued after the (one-shot)
|
|
801
|
+
// reconcile gate resolved — i.e. this is pure FIFO wait, not gate wait.
|
|
802
|
+
const queueWaitMs = Date.now() - queuedItem.enqueuedAt;
|
|
803
|
+
span.setAttribute("senpi.queue.wait_ms", queueWaitMs);
|
|
804
|
+
span.setAttribute("senpi.queue.depth", this.signalQueue.length);
|
|
805
|
+
recordSignalQueueWait(queueWaitMs / 1000, { scannerId: queuedItem.result.scannerId });
|
|
806
|
+
try {
|
|
807
|
+
const usedSlotsByStrategy = await this.stateManager.getUsedSlotsByStrategy([this.strategyConfig.address]);
|
|
808
|
+
const payload = buildActionScanPayload(queuedItem.result, this.strategyConfig, {
|
|
809
|
+
usedSlotsByStrategy,
|
|
810
|
+
address: queuedItem.result.address,
|
|
811
|
+
});
|
|
812
|
+
const hookEvent = {
|
|
813
|
+
type: HOOK_EVENT.ON_SIGNAL_DETECTED,
|
|
814
|
+
runtimeName: this.config.name,
|
|
815
|
+
address: queuedItem.result.address,
|
|
816
|
+
data: {
|
|
817
|
+
...payload,
|
|
818
|
+
__scanRunId: queuedItem.runId,
|
|
819
|
+
},
|
|
820
|
+
timestamp: new Date().toISOString(),
|
|
821
|
+
};
|
|
822
|
+
this.bus.emit(HOOK_EVENT.ON_SIGNAL_DETECTED, hookEvent);
|
|
823
|
+
// Serialize trade loop vs reconcile — reconcileMutex outer, key-lock inner.
|
|
824
|
+
await this.reconcileMutex.withKeyLock("reconcile", () => this.runActionsForSignal(hookEvent));
|
|
825
|
+
console.info("[senpi-runtime] [ingest-trace] runActionsForSignal complete", JSON.stringify({ address: queuedItem.result.address, scannerId: queuedItem.result.scannerId }));
|
|
826
|
+
}
|
|
827
|
+
catch (err) {
|
|
828
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
829
|
+
// Structured error log: normalizes to exception.* attributes and, since the catch
|
|
830
|
+
// swallows the error (so withSpan's auto-record never fires), records it on the active
|
|
831
|
+
// span + sets ERROR status. Replaces the prior console.error + manual span calls.
|
|
832
|
+
logger.error("signal processing error", err);
|
|
833
|
+
this.bus.emit("signal_processing_error", {
|
|
834
|
+
error: err,
|
|
835
|
+
address: queuedItem.result.address,
|
|
836
|
+
scannerId: queuedItem.result.scannerId,
|
|
837
|
+
runId: queuedItem.runId,
|
|
838
|
+
timestamp: new Date().toISOString(),
|
|
839
|
+
});
|
|
840
|
+
// First-class event log alongside the legacy bus emit. The build runs inside
|
|
841
|
+
// emitEvent's guard — telemetry never disturbs the consumer.
|
|
842
|
+
emitEvent(logger, () => buildRuntimeErrorEvent("signal_processing", queuedItem.result.scannerId, message));
|
|
843
|
+
}
|
|
844
|
+
});
|
|
795
845
|
});
|
|
796
846
|
}
|
|
797
847
|
}
|
|
@@ -852,23 +902,6 @@ export class Runtime {
|
|
|
852
902
|
}
|
|
853
903
|
const durationMs = Date.now() - t0;
|
|
854
904
|
const { adopted, resized, archived } = result.counts;
|
|
855
|
-
// Telemetry must never break reconcile control flow. bus.emit is a Node
|
|
856
|
-
// EventEmitter: a listener that throws synchronously makes emit re-throw,
|
|
857
|
-
// which would reject this loop and leave the gate forever closed. Contain it.
|
|
858
|
-
try {
|
|
859
|
-
this.bus.emit("tracking.runtime_reconciled", {
|
|
860
|
-
address,
|
|
861
|
-
data: { adopted, resized, archived, success: result.success, attempt, durationMs },
|
|
862
|
-
timestamp: new Date().toISOString(),
|
|
863
|
-
});
|
|
864
|
-
}
|
|
865
|
-
catch (err) {
|
|
866
|
-
logger.warn("[runtime][reconcile] tracking.runtime_reconciled listener threw; contained", {
|
|
867
|
-
address,
|
|
868
|
-
attempt,
|
|
869
|
-
err,
|
|
870
|
-
});
|
|
871
|
-
}
|
|
872
905
|
if (result.success) {
|
|
873
906
|
logger.info("[runtime][reconcile] boot reconcile succeeded", { address, attempt, adopted, resized, archived });
|
|
874
907
|
this.resolveReconcileGate();
|
|
@@ -887,17 +920,20 @@ export class Runtime {
|
|
|
887
920
|
gate.resolve();
|
|
888
921
|
}
|
|
889
922
|
/**
|
|
890
|
-
* Dispose the
|
|
891
|
-
*
|
|
923
|
+
* Dispose the domain-event subscriber. Idempotent; shared by stop() and the failed-start
|
|
924
|
+
* cleanup path in start().
|
|
892
925
|
*/
|
|
893
|
-
async
|
|
894
|
-
if (this.
|
|
895
|
-
this.
|
|
896
|
-
this.
|
|
926
|
+
async disposeSubscribers() {
|
|
927
|
+
if (this.domainEventSubscriber) {
|
|
928
|
+
this.domainEventSubscriber.dispose();
|
|
929
|
+
this.domainEventSubscriber = null;
|
|
897
930
|
}
|
|
898
|
-
if (this.
|
|
899
|
-
|
|
900
|
-
|
|
931
|
+
if (this.eventSinkAddress !== null) {
|
|
932
|
+
// Drain the sink's queued fire-and-forget appends before dropping it, so a graceful stop
|
|
933
|
+
// doesn't discard events that were enqueued but not yet written.
|
|
934
|
+
await flushEventSink(this.eventSinkAddress);
|
|
935
|
+
unregisterEventSink(this.eventSinkAddress);
|
|
936
|
+
this.eventSinkAddress = null;
|
|
901
937
|
}
|
|
902
938
|
}
|
|
903
939
|
async stop() {
|
|
@@ -912,15 +948,21 @@ export class Runtime {
|
|
|
912
948
|
}
|
|
913
949
|
// Resolve the gate so the consumer doesn't hang waiting for a reconcile that won't come.
|
|
914
950
|
this.reconcileGate?.resolve();
|
|
915
|
-
this.
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
951
|
+
const uptimeMs = Date.now() - (this.startedAt ?? Date.now());
|
|
952
|
+
// First-class event log. The build runs inside emitEvent's guard — telemetry never blocks shutdown.
|
|
953
|
+
emitEvent(logger, () => buildRuntimeStoppedEvent(VERSION, uptimeMs, this.strategyConfig.address));
|
|
954
|
+
if (this.queueDepthGaugeDispose) {
|
|
955
|
+
this.queueDepthGaugeDispose();
|
|
956
|
+
this.queueDepthGaugeDispose = null;
|
|
957
|
+
}
|
|
958
|
+
if (this.dslActivePositionsGaugeDispose) {
|
|
959
|
+
this.dslActivePositionsGaugeDispose();
|
|
960
|
+
this.dslActivePositionsGaugeDispose = null;
|
|
961
|
+
}
|
|
962
|
+
if (this.livenessHeartbeatTimer) {
|
|
963
|
+
clearInterval(this.livenessHeartbeatTimer);
|
|
964
|
+
this.livenessHeartbeatTimer = null;
|
|
965
|
+
}
|
|
924
966
|
this.signalConsumerStopped = true;
|
|
925
967
|
if (this.signalQueueWait) {
|
|
926
968
|
const w = this.signalQueueWait;
|
|
@@ -936,14 +978,6 @@ export class Runtime {
|
|
|
936
978
|
this.scannerModule.off("scanner:run:complete", this.onScannerRunComplete);
|
|
937
979
|
this.onScannerRunComplete = null;
|
|
938
980
|
}
|
|
939
|
-
if (this.onScannerRunSkip != null) {
|
|
940
|
-
this.scannerModule.off("scanner:run:skip", this.onScannerRunSkip);
|
|
941
|
-
this.onScannerRunSkip = null;
|
|
942
|
-
}
|
|
943
|
-
if (this.onScannerRunError != null) {
|
|
944
|
-
this.scannerModule.off("scanner:run:error", this.onScannerRunError);
|
|
945
|
-
this.onScannerRunError = null;
|
|
946
|
-
}
|
|
947
981
|
if (this.actionNotificationSubscriber != null) {
|
|
948
982
|
this.actionNotificationSubscriber.dispose();
|
|
949
983
|
this.actionNotificationSubscriber = null;
|
|
@@ -958,13 +992,7 @@ export class Runtime {
|
|
|
958
992
|
this.senpi = null;
|
|
959
993
|
}
|
|
960
994
|
this.healthStateModule = null;
|
|
961
|
-
|
|
962
|
-
await this.trackingHandler.dispose();
|
|
963
|
-
this.trackingHandler = null;
|
|
964
|
-
}
|
|
965
|
-
// Telemetry recording teardown: stop the subscriber, then flush + stop the batcher (best-effort)
|
|
966
|
-
// so the just-recorded runtime_stopped row ships before the process exits.
|
|
967
|
-
await this.disposeRecording();
|
|
995
|
+
await this.disposeSubscribers();
|
|
968
996
|
if (this.bus.removeAllListeners) {
|
|
969
997
|
this.bus.removeAllListeners();
|
|
970
998
|
}
|