{
  "format": "siebly-agent-recipe/v1",
  "id": "binance-position-manager",
  "title": "Position Management with Binance APIs & WebSockets",
  "lastReviewed": "2026-05-12",
  "package": {
    "ecosystem": "npm",
    "name": "binance",
    "install": "npm install binance",
    "docs": "https://siebly.io/sdk/binance/javascript",
    "repository": "https://github.com/tiagosiebler/binance"
  },
  "scope": {
    "runtime": "Node.js LTS",
    "language": "TypeScript",
    "products": [
      "Binance Spot",
      "Binance USD-M Futures"
    ],
    "defaultMode": "EXECUTION_MODE=DRY_RUN_PRIVATE for order-capable local runs",
    "executionMode": {
      "env": "EXECUTION_MODE",
      "values": [
        "PUBLIC",
        "READ_ONLY_PRIVATE",
        "DRY_RUN_PRIVATE",
        "DEMO",
        "TESTNET",
        "LIVE"
      ],
      "exchangeWritesOnlyWhen": "EXECUTION_MODE=DEMO, TESTNET, or LIVE plus venue routing, conformance, [risk gates](https://siebly.io/reference/glossary#risk-gate), credential checks, and manual acknowledgement gates"
    },
    "liveExecutionDefault": false,
    "credentials": "scoped API keys from environment variables only for READ_ONLY_PRIVATE, DRY_RUN_PRIVATE, DEMO, TESTNET, LIVE; exchange writes require EXECUTION_MODE=DEMO, TESTNET, or LIVE"
  },
  "requiredSources": [
    "https://siebly.io/ai/exchange-state",
    "https://siebly.io/.well-known/prompts/binance-position-manager/latest.md",
    "https://siebly.io/.well-known/recipes/binance-position-manager.json",
    "https://siebly.io/ai/exchange-state/binance",
    "https://siebly.io/.well-known/integration-kits/binance-position-manager/latest.json",
    "https://siebly.io/ai/algo-orders/binance",
    "https://siebly.io/.well-known/recipes/binance-usdm-algo-orders.json",
    "https://siebly.io/.well-known/agent-manifests/binance-position-manager/latest.json",
    "https://siebly.io/.well-known/agent-manifests/exchange-state-management/latest.json",
    "https://siebly.io/.well-known/runtime-kits/exchange-state-management/v1/index.json",
    "https://siebly.io/.well-known/runtime-kits/exchange-state-management/v1/types.ts",
    "https://siebly.io/.well-known/integration-kits/exchange-state-management/latest.json",
    "https://siebly.io/.well-known/conformance/exchange-state-management/latest.json",
    "https://siebly.io/.well-known/conformance/exchange-state-management/v1/schema.json",
    "https://siebly.io/.well-known/conformance/exchange-state-management/v1/fixtures.json",
    "https://siebly.io/.well-known/conformance/exchange-state-management/v1/runner.ts",
    "https://siebly.io/.well-known/conformance/binance-position-manager/latest.json",
    "https://siebly.io/ai/exchange-state",
    "https://siebly.io/.well-known/recipes/exchange-state-management.json"
  ],
  "fallbackSources": [
    "https://siebly.io/sdk/binance/javascript",
    "https://siebly.io/llms-tasks.txt",
    "https://siebly.io/.well-known/siebly-sdk-catalog.json",
    "https://github.com/tiagosiebler/binance",
    "https://github.com/sieblyio/crypto-api-examples/tree/master/examples/Binance"
  ],
  "primarySpec": {
    "id": "exchange-state-management-spec",
    "title": "Exchange State Management",
    "href": "https://siebly.io/ai/exchange-state",
    "purpose": "Exchange-neutral runtime spec for private account, order, and position state workflows, including DCA/TP/SL managers.",
    "architecture": {
      "reusable": "order_account_position_state_machine",
      "lane": "ws_symbol_side_action_gated"
    },
    "role": "Primary implementation spec. Other artifacts support, specialize, or test this workflow; they do not replace it."
  },
  "onePromptPath": [
    "Read primarySpec first",
    "Implement accountstate as the trusted WS cache",
    "Trigger debounced reconciliation from accountstate updates",
    "Gate exchange mutations by slot confirmation",
    "Use REST hydration only for startup, reconnect, recovery, or explicit sync-required states",
    "After implementation, generate/run applicable [behavior-contract fixtures](https://siebly.io/reference/glossary#behavior-contract-fixture) before DEMO, TESTNET, or LIVE"
  ],
  "antiTrace": {
    "normalPrivateWsBurstMustNot": [
      "private event -> REST hydrate",
      "REST acceptance -> trusted active order downgrade",
      "confirmed context -> recovery loop",
      "pending confirmation -> duplicate place",
      "execution fill -> open order confirmation"
    ]
  },
  "activeRiskNotes": [
    "Use the simple managed-slot lane for Binance: SDK-prefixed [Custom Order IDs](https://siebly.io/reference/glossary#custom-order-id) plus runtime order-context registry, recovery hydrate/rebuild, stream-first live state, regular fixed TP, and Algo SL.",
    "Use the fixed ws_symbol_side_action_gated architecture. Do not broaden it into a product-wide field-by-field reconciler.",
    "Keep Binance cancel-before-place guidance scoped to Binance close-position or conditional conflicts. Do not copy it into exchange-neutral or Bybit same-slot update rules.",
    "Do not use \"replace\" as shorthand for cancel/place. Classify each app-owned slot as keep, amend, cancel_place, cancel, or place, then apply Binance-specific cancel-before-place only where required.",
    "Do not recover lifecycle epoch, replacement generation, role, step, side, or order kind from Binance client IDs for the default manager; use IDs only as context lookup keys.",
    "Fixed TP and DCA use regular LIMIT orders. A DCA LIMIT may fill immediately at limit-or-better or rest at the submitted limit price; both are normal LIMIT behavior. Do not add maker-only, post-only, mark-price, quote-freshness, marketability, or forced-maker gates unless explicitly configured. Use the Algo path only for SL, trailing stop, or explicitly configured conditional TP behavior.",
    "Do not turn sync_required, rejected submission, or unknown state into a permanent operator pause. Use recoveryRequired or syncRequired, block normal action families until scoped hydration restores trusted state, then requeue and replan.",
    "Use scoped REST hydration for startup, restart, reconnect, stream exception or gap, missing prerequisites such as filters, unknown submit/cancel/amend outcomes, timeouts, sync-required or not-ready state, conflicting evidence, and explicit recovery. It is not the ordinary response to every healthy private event or ordinary pending confirmation."
  ],
  "reusablePrimitives": {
    "architecture": "order_account_position_state_machine",
    "imports": [
      "custom-order-id-registry",
      "trusted-accountstate-boundary",
      "subject-level-trust-boundary",
      "position-state-update-trigger",
      "symbol-scope-auto-detect",
      "risk-geometry-validation",
      "ws-first-order-state",
      "recovery-hydrate-replan",
      "affected-scope-event-routing",
      "protective-sl-tp-dispatch",
      "mutation-confirmation-gating",
      "stale-mutation-noop-classification",
      "slot-convergence",
      "latch-lifecycle",
      "conformance-fixture-schema",
      "identity-chain-acceptance-gate"
    ],
    "rules": [
      "custom-order-id-registry: [Custom Order IDs](https://siebly.io/reference/glossary#custom-order-id) are lookup keys into one order-context registry/store. Generate a unique random ID, store context before submit, send the order with that ID, and resolve exchange echoes through the store. Follow exchange-specific prefix, length, and character rules only when required. Keep product, symbol, role, side, step, order kind, lifecycle, generation, recovery state, and other strategy state out of the ID text.",
      "trusted-accountstate-boundary: REST submission acceptance is provisional coordination evidence. Trusted order/position state comes from private WS/accountstate ingestion or scoped REST recovery hydration.",
      "subject-level-trust-boundary: Split trust by subject: order trust, position trust, filter trust, context trust, and readiness trust. A TP/SL/DCA order update proves only order trust; it does not prove position trust, position size, entry/cost basis, exposure, or replacement eligibility. For products with exchange-provided position rows, order/fill events are triggers; replacement planning waits for matching position trust from private position or account updates or scoped recovery. For products without exchange-provided position rows, derive local position state from fills/executions, fees, account events, balance updates, and documented matching rules before managed exits, exposure changes, or re-hedging.",
      "position-state-update-trigger: For products with exchange-provided position rows, private order and fill events trigger reconciliation but replacement, DCA, cleanup, and re-protection planning waits for matching trusted position or account-state evidence or scoped recovery. Products without exchange-provided position rows must derive local position state explicitly from fills/executions, fees, account events, and balance updates.",
      "symbol-scope-auto-detect: If configuredSymbols is blank, absent, or empty, auto-detect eligible open positions. When symbols are configured, treat them as an allowlist: manage matching detected positions only and ignore or log out-of-scope private events without mutation. Sample symbols from docs, tests, prompts, or quickstarts are examples only; never use them as runtime defaults.",
      "risk-geometry-validation: For broad TP/SL/DCA position managers, use percentage-based strategy inputs by default: derive TP, DCA, and SL prices plus DCA size from trusted entry and position size before order planning. Absolute TP/DCA/SL prices or DCA quantities are advanced per-symbol operator overrides, not the primary config model. If allowed, they must be explicit, scoped, compatible with percentage defaults, and validated through the same filters and risk geometry. Startup validation rejects missing, invalid, contradictory, or non-finite strategy inputs before private clients, WebSocket subscriptions, hydration, or exchange mutation. Validate risk geometry before exchange mutation: for long positions, TP is above entry, DCA is below entry, and SL is below DCA; for short positions, TP is below entry, DCA is above entry, and SL is above DCA. Reject missing or invalid TP/DCA/SL strategy outputs before order placement. After derivation or override, quantize prices and quantities with hydrated exchange filters before final validation. After quantization, revalidate risk geometry, min/max, and notional rules; reject only if the quantized TP/DCA/SL values are equal, crossed, or otherwise violate geometry or filters before [EXECUTION_MODE](https://siebly.io/reference/glossary#execution-mode)=DRY_RUN_PRIVATE, DEMO, TESTNET, or LIVE order placement. Risk geometry validation uses the trusted entry price or explicit operator override, hydrated tick/lot filters, and the managed side before any place/amend/cancel request.",
      "ws-first-order-state: Private account/order events update accountstate immediately and may arrive before REST promises resolve. Register custom ID context before sending any REST order request.",
      "recovery-hydrate-replan: Unknown, rejected, conflicting, reconnect, or sync-required state enters scoped recovery. Recovery hydrates affected positions, open orders, fills/executions, and account readiness, clears the latch on success, requeues the affected scope, and replans from trusted accountstate.",
      "affected-scope-event-routing: Ingest relevant private events immediately, but schedule planning only for precise affected symbol-side scopes. Broad unknowns become maintenance or scoped recovery, not product-wide churn by default.",
      "protective-sl-tp-dispatch: For fresh protection, pre-register SL and TP order contexts and dispatch both separate orders concurrently by default. Classify partial outcomes by failure reason and keep exposure-increasing DCA gated until required protection is trusted.",
      "mutation-confirmation-gating: Normal exposure-increasing, replacement, and DCA work advances only after private confirmation or scoped recovery proves the prior outcome.",
      "stale-mutation-noop-classification: Treat stale cancel/amend/no-change responses as idempotent only when current trusted accountstate proves target absence or slot equivalence. Otherwise run scoped recovery.",
      "slot-convergence: Compare desired and active orders by actionable slot fields for the order kind, not by raw request object equality, generated IDs, or parsed custom-ID state. When an accountstate or exchange-overlay comparison helper is available, compare NormalizedOrder-to-NormalizedOrder: convert desired slot/request objects into the accountstate NormalizedOrder shape first, mapping local managedSide/managedStrategySide to strategySide, then compare them with active normalized orders. Do not pass strategy-local DesiredManagedOrder/request objects directly or hand-roll raw exchange-object equality.",
      "latch-lifecycle: Every startup cleanup, recovery, sync-required, pending-confirmation, and readiness latch needs entry conditions, blocked behavior, no-work exit, success exit, failure behavior, and next action.",
      "conformance-fixture-schema: Executable fixtures should include initial accountstate, event or REST result, expected accountstate mutation, affected scopes, selected action family, submission behavior, logs, and latch state.",
      "identity-chain-acceptance-gate: Trace the full identity chain: config scope -> product/environment/account -> symbol -> position mode -> managed side -> exchange position identity -> accountstate position state (native or locally derived) -> planner scope -> slot scope -> custom order ID -> durable context -> exchange request -> REST acceptance -> private order/execution/position event -> trusted active order -> subject trust state -> confirmation tracker -> recovery scope -> cleanup/protective/DCA replanning. Do not mark the implementation complete until three consecutive full identity-chain review passes produce no code, tests, fixtures, or documentation changes. Trace mismatched, stale, missing, contradictory, duplicated, late, recovered, and flat identities across every runtime boundary. Every accepted lifecycle claim needs an executable fixture; behaviors without fixtures must be listed as unsupported or unverified. Core [behavior-contract fixtures](https://siebly.io/reference/glossary#behavior-contract-fixture) cover context write failure before submit, early private confirmation before REST accept, one-way side flips, pending duplicate place/cancel guards, and decimal/default-equivalent active-order convergence. The [EXECUTION_MODE](https://siebly.io/reference/glossary#execution-mode)=DEMO, TESTNET, or LIVE submission paths are implemented for order-capable projects where supported, but they remain disabled until the required identity-chain, subject-trust, symbol-scope, and risk-geometry fixtures exist and pass."
    ]
  },
  "subjectTrust": {
    "subjects": [
      "order trust",
      "position trust",
      "filter trust",
      "context trust",
      "readiness trust"
    ],
    "rules": [
      "Split trust by subject: order trust, position trust, filter trust, context trust, and readiness trust.",
      "A TP/SL/DCA order update proves only order trust; it does not prove position trust, position size, entry/cost basis, exposure, or replacement eligibility.",
      "For products with exchange-provided position rows, order/fill events are triggers; replacement planning waits for matching position trust from private position or account updates or scoped recovery.",
      "For products without exchange-provided position rows, derive local position state from fills/executions, fees, account events, balance updates, and documented matching rules before managed exits, exposure changes, or re-hedging."
    ]
  },
  "symbolScope": [
    "If configuredSymbols is blank, absent, or empty, auto-detect eligible open positions.",
    "When symbols are configured, treat them as an allowlist: manage matching detected positions only and ignore or log out-of-scope private events without mutation.",
    "Sample symbols from docs, tests, prompts, or quickstarts are examples only; never use them as runtime defaults."
  ],
  "riskGeometry": [
    "For broad TP/SL/DCA position managers, use percentage-based strategy inputs by default: derive TP, DCA, and SL prices plus DCA size from trusted entry and position size before order planning.",
    "Absolute TP/DCA/SL prices or DCA quantities are advanced per-symbol operator overrides, not the primary config model. If allowed, they must be explicit, scoped, compatible with percentage defaults, and validated through the same filters and risk geometry.",
    "Startup validation rejects missing, invalid, contradictory, or non-finite strategy inputs before private clients, WebSocket subscriptions, hydration, or exchange mutation.",
    "Validate risk geometry before exchange mutation: for long positions, TP is above entry, DCA is below entry, and SL is below DCA; for short positions, TP is below entry, DCA is above entry, and SL is above DCA.",
    "Reject missing or invalid TP/DCA/SL strategy outputs before order placement. After derivation or override, quantize prices and quantities with hydrated exchange filters before final validation.",
    "After quantization, revalidate risk geometry, min/max, and notional rules; reject only if the quantized TP/DCA/SL values are equal, crossed, or otherwise violate geometry or filters before [EXECUTION_MODE](https://siebly.io/reference/glossary#execution-mode)=DRY_RUN_PRIVATE, DEMO, TESTNET, or LIVE order placement.",
    "Risk geometry validation uses the trusted entry price or explicit operator override, hydrated tick/lot filters, and the managed side before any place/amend/cancel request."
  ],
  "identityChainReview": {
    "cleanPassesRequired": 3,
    "chain": [
      "config scope",
      "product/environment/account",
      "symbol",
      "position mode",
      "managed side",
      "exchange position identity",
      "accountstate position state (native or locally derived)",
      "planner scope",
      "slot scope",
      "custom order ID",
      "durable context",
      "exchange request",
      "REST acceptance",
      "private order/execution/position event",
      "trusted active order",
      "subject trust state",
      "confirmation tracker",
      "recovery scope",
      "cleanup/protective/DCA replanning"
    ],
    "requiredRule": "Do not mark the implementation complete until three consecutive full identity-chain review passes produce no code, tests, fixtures, or documentation changes.",
    "passMustTrace": "Trace mismatched, stale, missing, contradictory, duplicated, late, recovered, and flat identities across every runtime boundary."
  },
  "finalAcceptanceGate": [
    "Trace the full identity chain: config scope -> product/environment/account -> symbol -> position mode -> managed side -> exchange position identity -> accountstate position state (native or locally derived) -> planner scope -> slot scope -> custom order ID -> durable context -> exchange request -> REST acceptance -> private order/execution/position event -> trusted active order -> subject trust state -> confirmation tracker -> recovery scope -> cleanup/protective/DCA replanning.",
    "Do not mark the implementation complete until three consecutive full identity-chain review passes produce no code, tests, fixtures, or documentation changes.",
    "Trace mismatched, stale, missing, contradictory, duplicated, late, recovered, and flat identities across every runtime boundary.",
    "Every accepted lifecycle claim needs an executable fixture; behaviors without fixtures must be listed as unsupported or unverified.",
    "Core [behavior-contract fixtures](https://siebly.io/reference/glossary#behavior-contract-fixture) cover context write failure before submit, early private confirmation before REST accept, one-way side flips, pending duplicate place/cancel guards, and decimal/default-equivalent active-order convergence.",
    "The [EXECUTION_MODE](https://siebly.io/reference/glossary#execution-mode)=DEMO, TESTNET, or LIVE submission paths are implemented for order-capable projects where supported, but they remain disabled until the required identity-chain, subject-trust, symbol-scope, and risk-geometry fixtures exist and pass."
  ],
  "sdkSurfacesToVerify": {
    "restClients": {
      "spot": "MainClient",
      "usdmFutures": "USDMClient"
    },
    "websocketClient": "WebsocketClient",
    "userDataStreams": {
      "spot": "subscribeSpotUserDataStream",
      "usdmFutures": "subscribeUsdFuturesUserDataStream"
    },
    "websocketEvents": [
      "open",
      "response",
      "formattedMessage",
      "formattedUserDataMessage",
      "reconnecting",
      "reconnected",
      "exception"
    ],
    "shutdown": "closeAll(true) or the current documented closeAll variant",
    "spotHydration": [
      "getExchangeInfo",
      "getAccountInformation",
      "getOpenOrders",
      "getAllOrders",
      "getAccountTradeList"
    ],
    "usdmHydration": [
      "getExchangeInfo",
      "getPositionsV3",
      "getAllOpenOrders",
      "getOpenAlgoOrders",
      "getAccountTrades",
      "getAllOrders",
      "getAccountInformationV3",
      "getCurrentPositionMode",
      "getMultiAssetsMode",
      "getFuturesSymbolConfig",
      "getNotionalAndLeverageBrackets"
    ],
    "orderMethods": {
      "spot": [
        "submitNewOrder",
        "cancelOrder",
        "testNewOrder"
      ],
      "usdmRegular": [
        "submitNewOrder",
        "cancelOrder",
        "testOrder"
      ],
      "usdmAlgoConditional": [
        "submitNewAlgoOrder",
        "cancelAlgoOrder"
      ]
    },
    "clientOrderIdFields": {
      "spotAndUsdmRegular": "newClientOrderId",
      "usdmAlgoConditional": "clientAlgoId"
    },
    "formattedPrivateEventFieldMatrix": {
      "sdkSurfaceCheck": {
        "reviewedAgainst": "binance npm package 3.5.8 on 2026-05-11",
        "declarationFiles": [
          "lib/types/websockets/ws-events-formatted.d.ts",
          "lib/util/beautifier-maps.js",
          "lib/util/typeGuards.js"
        ],
        "rule": "Implementations must re-verify these formatted paths against the installed binance package before exchange calls. If declarations differ, update the adapter and fixtures before enabling EXECUTION_MODE=DEMO, TESTNET, or LIVE submission."
      },
      "events": [
        {
          "eventType": "ORDER_TRADE_UPDATE",
          "formattedType": "WsMessageFuturesUserDataTradeUpdateEventFormatted",
          "typeGuard": "isWsFormattedFuturesUserDataTradeUpdateEvent",
          "paths": {
            "eventType": "event.eventType",
            "symbol": "event.order.symbol",
            "customClientId": "event.order.clientOrderId",
            "exchangePositionSide": "event.order.positionSide",
            "orderSide": "event.order.orderSide",
            "orderType": "event.order.orderType",
            "executionType": "event.order.executionType",
            "orderStatus": "event.order.orderStatus",
            "closeAll": "event.order.isCloseAll"
          },
          "trust": "Order or fill evidence only. It may clear matching pending order confirmation, but replacement planning waits for matching position trust or scoped recovery."
        },
        {
          "eventType": "ALGO_UPDATE",
          "formattedType": "WsMessageFuturesUserDataAlgoUpdateFormatted",
          "typeGuard": "isWsFormattedFuturesAlgoUpdateEvent",
          "paths": {
            "eventType": "event.eventType",
            "symbol": "event.algoOrder.symbol",
            "customClientId": "event.algoOrder.clientAlgoId",
            "exchangePositionSide": "event.algoOrder.positionSide",
            "orderSide": "event.algoOrder.side",
            "orderType": "event.algoOrder.orderType",
            "algoStatus": "event.algoOrder.algoStatus",
            "closePosition": "event.algoOrder.closePosition",
            "triggerPrice": "event.algoOrder.triggerPrice"
          },
          "trust": "Algo order evidence only. It must not be read from root clientAlgoId and must not unlock DCA or replacement without position trust."
        },
        {
          "eventType": "TRADE_LITE",
          "formattedType": "WsMessageFuturesUserDataTradeLiteEventFormatted",
          "typeGuard": "event.eventType === \"TRADE_LITE\"",
          "paths": {
            "eventType": "event.eventType",
            "symbol": "event.symbol",
            "customClientId": "event.clientOrderId",
            "orderSide": "event.side",
            "lastFilledPrice": "event.lastFilledPrice",
            "lastFilledQuantity": "event.lastFilledQuantity",
            "tradeId": "event.tradeId",
            "orderId": "event.orderId"
          },
          "trust": "Fill evidence only. This formatted event has no positionSide path; route by order-context registry when possible, otherwise mark the symbol broad or both one-way candidates until ACCOUNT_UPDATE resolves position trust."
        },
        {
          "eventType": "ACCOUNT_UPDATE",
          "formattedType": "WsMessageFuturesUserDataAccountUpdateFormatted",
          "typeGuard": "isWsFormattedFuturesUserDataAccountUpdate",
          "paths": {
            "eventType": "event.eventType",
            "transactionTime": "event.transactionTime",
            "updateEventType": "event.updateData.updateEventType",
            "positionRows": "event.updateData.updatedPositions[]",
            "positionSymbol": "event.updateData.updatedPositions[].symbol",
            "exchangePositionSide": "event.updateData.updatedPositions[].positionSide",
            "positionAmount": "event.updateData.updatedPositions[].positionAmount",
            "entryPrice": "event.updateData.updatedPositions[].entryPrice",
            "balanceRows": "event.updateData.updatedBalances[]"
          },
          "trust": "Position trust for the matching product/symbol/position row. DCA, TP, SL, full close, and same-side add replans should key off matching position evidence or scoped recovery."
        }
      ],
      "negativeRules": [
        "Do not look for root newClientOrderId on formatted USD-M ORDER_TRADE_UPDATE; use order.clientOrderId.",
        "Do not look for root clientAlgoId on formatted USD-M ALGO_UPDATE; use algoOrder.clientAlgoId.",
        "Do not create unresolved side scopes from TRADE_LITE. Use registry context or broad symbol/both-candidate routing until ACCOUNT_UPDATE provides positionSide.",
        "Missing required formatted paths for an event that should clear a pending confirmation enters scoped recovery; it must not mutate an unscoped slot."
      ]
    }
  },
  "terminologyWarnings": [
    "Binance uses newClientOrderId and clientAlgoId, not orderLinkId.",
    "Binance USD-M futures uses positionSide, not positionIdx.",
    "Binance close-all conditional orders use closePosition, not closeOnTrigger.",
    "Verify reduceOnly, workingType, priceProtect, closePosition, and positionSide combinations from current docs and package types before live use."
  ],
  "workflow": [
    "Start from the agent implementation manifest and integration kit, then generate a local checklist covering SDK/API surfaces, request builders, skeleton modules, decision trees, fixture coverage, and write-capable execution gates before writing exchange code.",
    "Store docs/AI_PROMPT.md (or docs/SPEC.md when that is the project standard) with the exact generated prompt and docs/AI_PROMPT_MANIFEST.json with the selected options, linked artifacts, package versions recorded after install, write-capable execution gates, and critical fixture names.",
    "Load scoped credentials from environment variables and verify that secret values are never logged.",
    "Create MainClient, USDMClient, and WebsocketClient only for the enabled product scopes. For EXECUTION_MODE=DRY_RUN_PRIVATE, DEMO, TESTNET, or LIVE REST request paths, prefer options such as beautifyResponses=false, filterUndefinedParams=true, and strictParamValidation=true where the current SDK supports them.",
    "Hydrate exchange filters, account state, open orders, fills, balances, position mode, margin mode, and futures risk limits over REST at startup, reconnect, exception, sync-required, submission-recovery, or conflict boundaries. Store the hydrated filters in product/symbol state and pass those stored filters into the planner.",
    "Treat startup and reconnect REST hydration for positions, regular open orders, and open Algo orders as a replacement view of currently open exchange state for the hydrated product/symbol scope. App-owned orders absent from the current open-order view are terminal or stale unless newer user-data evidence proves otherwise.",
    "On restart, merge open orders and recent history carefully. Current open app-owned orders and pending confirmations must not be overwritten by older terminal history for the same custom ID. If REST confirms an app-owned order is open but omits or normalizes fields needed for slot convergence, preserve locally registered planned actionable fields for that custom ID. Newer terminal user-data events or newer history may close local state. If timestamps or statuses conflict, enter recoveryRequired for reconciliation rather than submitting.",
    "Connect private user-data streams and treat transport open, stream readiness, REST hydration, buffered replay, and manager readiness as separate states.",
    "For Binance user-data streams through this SDK, do not treat ordinary account-event idleness as stream failure while the transport is healthy. Enter recoveryRequired on SDK reconnecting or exception events, then hydrate REST state and replay buffered events on reconnected before resuming new exposure.",
    "Every classified user-data event must be applied to accountstate and logged semantically. Pending-confirmation matches may schedule immediate reconciliation; ACCOUNT_UPDATE position subjects should wait briefly by symbol-side so related events can arrive before planning; other order, fill, trade, Algo, cancel, and reject events are state-ingestion-first unless they clear pending confirmation or record a precise affected scope.",
    "This is a long-running service pattern. Do not implement run-once order-management mode for private exchange-state managers.",
    "Choose one private user-data processing path. Prefer formattedUserDataMessage for private state, or dedupe explicitly if formattedMessage is also inspected.",
    "Before routing private events, build and test a formatted event field-path matrix for ORDER_TRADE_UPDATE, ALGO_UPDATE, TRADE_LITE, and ACCOUNT_UPDATE. For current formatted USD-M events, regular order confirmations use order.clientOrderId, Algo confirmations use algoOrder.clientAlgoId, TRADE_LITE uses root clientOrderId with no positionSide, and position trust comes from ACCOUNT_UPDATE updateData.updatedPositions[].",
    "Track eligible positions by product, symbol, strategy side, exchange positionSide, size, entry price, account mode, and risk scope. This includes manually opened positions and automated positions the app is configured to manage. In USD-M one-way mode, positionSide=BOTH is not the managed side: infer LONG or SHORT from the signed positionAmt while still sending positionSide=BOTH in requests.",
    "If configuredSymbols is blank, absent, or empty, auto-detect eligible open positions. When symbols are configured, treat them as an allowlist: manage matching detected positions only and ignore or log out-of-scope private events without mutation. Sample symbols from docs, tests, prompts, or quickstarts are examples only; never use them as runtime defaults.",
    "Split trust by subject: order trust, position trust, filter trust, context trust, and readiness trust. Binance order or trade updates can prove order/fill evidence only; USD-M replacement planning waits for matching ACCOUNT_UPDATE position trust or scoped recovery.",
    "For Binance products without exchange-provided position rows, including Spot, derive local position state from fills/executions, fees, account events, balance updates, and documented matching rules before enabling any TP/SL/DCA-like behavior.",
    "Validate risk geometry before exchange mutation: for long positions, TP is above entry, DCA is below entry, and SL is below DCA; for short positions, TP is below entry, DCA is above entry, and SL is above DCA.",
    "Classify existing open orders by order-context registry/store lookup when available and never cancel unowned manual orders by default. If the runtime store is lost, do not parse custom IDs for slot meaning.",
    "If the Node.js project uses environment variables or creates .env.example, make .env loading automatic for every normal local entrypoint before config parsing. Prefer Node.js built-in --env-file/--env-file-if-exists in package scripts when supported by the project runtime; otherwise use process.loadEnvFile, dotenv/config, or the repo-local env loader. Document that real process environment variables override .env. Ensure all variables in the .env.example are commented clearly with their purpose and accepted values, and that the README references the .env.example and documents .env loading and precedence.",
    "For TypeScript CLIs, use Node16, NodeNext, or the repo-compatible module/moduleResolution settings, and omit undefined optional REST fields instead of sending undefined values.",
    "Order-capable execution mode contract: implement one environment variable, EXECUTION_MODE, with exactly these values: PUBLIC, READ_ONLY_PRIVATE, DRY_RUN_PRIVATE, DEMO, TESTNET, LIVE. Set the default for order-capable local runs and .env.example to EXECUTION_MODE=DRY_RUN_PRIVATE. PUBLIC uses no API keys and cannot create private clients, account readers, [order intents](https://siebly.io/reference/glossary#order-intent), or exchange write requests. READ_ONLY_PRIVATE may use read-only credentials for balances, orders, fills, native positions, or local position-derivation inputs, but cannot place, amend, cancel, borrow, transfer, lever, or otherwise mutate exchange state. DRY_RUN_PRIVATE may use private state and must build the exact place/amend/cancel request objects that DEMO, TESTNET, or LIVE would send, but the submitter records them without calling exchange mutation endpoints. DEMO and TESTNET are write-capable only when the selected exchange supports those non-production venues; if unsupported, they must fail closed with a clear configuration error and must never silently route to production. DEMO may call place/amend/cancel endpoints only against the selected exchange's demo or sandbox environment, and TESTNET may call them only against the selected exchange's testnet environment. LIVE is the only mode that may call production exchange place/amend/cancel endpoints. The finished order-capable project must include the LIVE execution path for the selected exchange and supported DEMO/TESTNET paths where those venues exist; do not leave LIVE submission as a TODO.",
    "Implement execution for when [EXECUTION_MODE](https://siebly.io/reference/glossary#execution-mode)=DEMO, TESTNET, or LIVE is enabled and all gates pass, but keep that path disabled by default. [EXECUTION_MODE](https://siebly.io/reference/glossary#execution-mode)=DRY_RUN_PRIVATE is the default execution mode, where the manager builds and logs DCA, take-profit, stop-loss, and trailing order candidates without submitting to the exchange. Always handle incoming account state events to keep internal account state in sync with exchange state, so the system is ready to execute live if requested by the user.",
    "Default DCA to one pending next step at a time. Treat full pre-placed DCA ladders as explicit opt-in behavior.",
    "For a new managed position with no app-owned orders, submit cleanup first when needed, read trusted account state, pre-register protective SL/TP contexts, dispatch separate SL and TP orders concurrently by default in the protective action family, wait for private stream confirmation or scoped recovery hydration, and submit exposure-increasing DCA only in a later DCA action family if the position still exists and still needs DCA. A DCA rejection must not prevent attempts to place protective exits.",
    "Treat TP/SL and app-owned DCA orders as simple managed slots. Classify each slot as keep, amend, cancel_place, cancel, or place by role, step, side, kind, and actionable slot fields. Use Binance-specific cancel-before-place only where current docs prove the slot cannot be amended or a close-position conditional conflict exists.",
    "Use Binance [Custom Order IDs](https://siebly.io/reference/glossary#custom-order-id) as order-context lookup keys only. For the default manager, keep product, symbol, role, side, step, order kind, lifecycle, generation, recovery state, and other strategy state out of the ID text.",
    "On startup, reconnect, recoveryRequired, or conflicting-state recovery, hydrate first, manage known app-owned slots from the registry/store, optionally clean unknown scoped orders only when config enables it, then rebuild the desired managed-slot set from current positions and trusted account state. Manual or unowned orders remain untouched by default.",
    "Fixed TP and DCA use regular LIMIT orders. A DCA LIMIT may fill immediately at limit-or-better or rest at the submitted limit price; both are normal LIMIT behavior. Do not add maker-only, post-only, mark-price, quote-freshness, marketability, or forced-maker gates unless explicitly configured. USD-M Algo orders are for close-position SL, trailing stops, or explicitly requested conditional TP behavior, not the default fixed TP slot.",
    "Use the Binance SDK order ID utilities for every [Custom Order ID](https://siebly.io/reference/glossary#custom-order-id) field, including newClientOrderId and clientAlgoId. Prefer generateNewOrderId(...) or client.generateNewOrderId(). Use getOrderIdPrefix(...) or client.getOrderIdPrefix() only when building a custom random suffix. Keep the final value inside Binance limits and store all strategy context in the order-context registry.",
    "Serialize the order workflow with the fixed ws_symbol_side_action_gated design. Reconciliation, buffered event replay, planning, and DEMO, TESTNET, or LIVE submission must not overlap. Affected work items are symbol-side scoped. Each reconciliation pass chooses one [action family](https://siebly.io/reference/glossary#action-family) only: recover uncertain state, clean up stale app-owned orders, repair/place protection, place/repair DCA, do nothing, or wait because required evidence or configuration is missing.",
    "Defer user-data-triggered replans while reconciliation, buffered replay, planning, or submission is active. The active owner should apply buffered events, record bounded follow-up reasons, and run one follow-up pass. Idle user-data replans should use stream-fed accountstate unless trust is unresolved.",
    "If the project-local state layer reports readyToTrade=false, sync_required, or outstanding syncRequests, satisfy the requested subjects with scoped REST hydration, then schedule a normal product reconciliation before planning or submitting.",
    "Expected own-order NEW confirmations and deferred user_data_* replans should be logged at info level, not warn, when the symbol-side workflow is behaving normally.",
    "Skip an already-drained deferred user_data_* replan only when bufferedEventCount is zero and every deferred reason starts with user_data_.",
    "After Binance accepts a DEMO, TESTNET, or LIVE order, record a pending confirmation, emit a sanitized accepted-submission log with request diff/context, and clear the accepted client ID from the in-flight set before waiting for user-data stream confirmation.",
    "If later private stream confirmation or scoped REST recovery proves a pending confirmation is absent after a short configured grace window, mark that local pending state stale so it cannot block missing DCA/TP/SL recreation forever.",
    "On deterministic DEMO, TESTNET, or LIVE request/config rejection, block and surface the failed slot and dependent exposure-increasing workflow while keeping ingestion and safe recovery alive. On unknown, network, timeout, thrown, or conflicting submission state, use the configured confirmation timeout, then enter scoped recoveryRequired with operatorPaused=false for the affected scope if still unknown.",
    "If slot-classifier output contains both cancels and placements for Binance-only non-amendable or identity-changing slots, run cancel-before-place as separate action-family passes: submit app-owned cancels first, wait for private-stream confirmation or scoped recovery hydration, replan from accountstate, and place only from the refreshed plan.",
    "For DEMO, TESTNET, or LIVE submissions, handle accepted, rejected, expired, cancelled, and unknown states explicitly and enter recoveryRequired on exchange rejection until reconciliation.",
    "For USD-M one-way short positions, keep exchange positionSide=BOTH but manage strategy side SHORT: DCA adds with SELL above entry, and TP/SL close with BUY. In one-way long, DCA adds with BUY and exits use SELL.",
    "Before placing new orders after hydration, emit cleanup intents for stale wrong-side, closed-position, wrong-kind, or extra app-owned orders first, including old DCA orders that could reopen exposure.",
    "Use slot-based convergence instead of raw field-by-field comparison. Regular TP and DCA LIMIT slots converge by product, symbol, exchange positionSide, managed strategy side, role, step, order side, quantity, price, and regular-order kind. Close-position Algo SL slots converge by product, symbol, exchange positionSide, managed strategy side, role, step, order side, trigger price, workingType, closePosition semantics, and Algo stop kind. Leave opposite hedge-side orders alone.",
    "When an accountstate or exchange-overlay comparison helper is available, compare NormalizedOrder-to-NormalizedOrder: convert desired slot/request objects into the accountstate NormalizedOrder shape first, mapping local managedSide/managedStrategySide to strategySide, then compare them with active normalized orders. Do not pass strategy-local DesiredManagedOrder/request objects directly or hand-roll raw exchange-object equality.",
    "Normalize desired and hydrated app-owned orders before comparing: numeric strings compare by tick/step-normalized decimal value; omitted close-position quantity or price can equal hydrated 0 or 0.0; hydrated reduceOnly, priceProtect, closePosition echo/defaults, regular-order trigger-only defaults, and generated client ID drift are diagnostic after slot convergence fields match.",
    "If app-owned DCA/TP/SL orders are manually cancelled while the position remains open and operatorPaused is false, the next reconciliation should recreate the missing managed orders.",
    "In hedge mode, manage simultaneous LONG and SHORT positions on the same symbol as separate product/symbol/positionSide/managed-side scopes; closing, cancelling, or cleaning one side must preserve the other side and its app-owned orders.",
    "For USD-M fixed TP, use regular submitNewOrder LIMIT with newClientOrderId. For USD-M close-position SL, use Algo STOP_MARKET with closePosition=true, clientAlgoId, and no quantity or reduceOnly. Conditional TP through Algo TAKE_PROFIT is an explicit advanced option only after current docs and package types verify it.",
    "If cancelAlgoOrder or cancelOrder returns -2011 Unknown order for an app-owned order that is absent from current open regular or open Algo hydration, mark it terminal/stale and stop retrying the cancel forever.",
    "Classify -2021 Order would immediately trigger and -4130 existing close-position order conflicts as recoverable outcomes that stop the active placement action and route through reconcile/replan rather than crashing the service.",
    "For DCA quantity multipliers, check positionQuantity * multiplier against the hydrated step size. If the quantized quantity is zero or below the minimum notional, block the intent locally and show the operator the minimum usable multiplier.",
    "Do not round with binary floating arithmetic and then call String(number). Format final request price and quantity strings from hydrated tickSize and stepSize decimal precision, so values such as 74992.800000000003 with tickSize 0.1 become 74992.8.",
    "Hydrate USD-M regular open orders and open Algo orders separately. Join recent fills from getAccountTrades(...) to recent orders from getAllOrders(...) where needed for terminal evidence and custom ID correlation; recover role and step from the order-context store, not by parsing the custom ID.",
    "Classify formatted user-data events from verified field paths, not broad root-field guesses. In current USD-M formatted events: ORDER_TRADE_UPDATE uses order.symbol, order.clientOrderId, and order.positionSide; ALGO_UPDATE uses algoOrder.symbol, algoOrder.clientAlgoId, and algoOrder.positionSide; TRADE_LITE uses root symbol and clientOrderId and has no positionSide; ACCOUNT_UPDATE position trust uses updateData.updatedPositions[].symbol, positionSide, positionAmount, and entryPrice. If logs also need a full JSON attempt, wrap stringify in a safe helper and fall back to a selected-field summary when the event is circular or too large.",
    "Redact user-data [wsKey values](https://siebly.io/reference/glossary#ws-key) as sensitive material because they may contain listen-key-like tokens even when the field is not named listenKey.",
    "After SDK reconnecting, reconnected, exception, exchange rejection, or unknown submission state, enter recoveryRequired or syncRequired, keep private streams connected and buffering where possible, hydrate REST state again, replay buffered events, reconcile app-owned orders, then re-enable new exposure only after readiness is coherent.",
    "Apply a rate-limit-aware reconciliation policy: full startup/reconnect/unknown-state hydration is immediate; own-order user_data_* events during an active workflow are buffered for the owner; idle account/order events may wait briefly for related events and reconcile once per affected symbol-side rather than spending REST weight for every ACCOUNT_UPDATE.",
    "Submission must stay inside the active symbol-side workflow. Do not reacquire the same workflow lock for an internal submit helper, and skip empty submit actions without recording workflow_already_active.",
    "On shutdown, cancel only configured app-owned transient orders if the user opted into that behavior, close WebSockets, and flush final state/logs. Log a compact store summary, not full hydrated filters or raw payloads, and use a bounded shutdown timeout around SDK/WebSocket close paths that do not prove completion.",
    "Doctor, inspect, status, readback, and similar commands must force EXECUTION_MODE=PUBLIC or READ_ONLY_PRIVATE, strip credentials and execution acknowledgements, and never inherit EXECUTION_MODE=DEMO, TESTNET, or LIVE order placement/cancel/amend settings from .env.",
    "Write-capable startup should also require a current .runtime/verified.json marker written by a safe verification command after build, tests, and critical conformance pass."
  ],
  "startupSequence": [
    "Load config, credentials, product scope, and EXECUTION_MODE; use EXECUTION_MODE=DRY_RUN_PRIVATE for order-capable local runs.",
    "Create REST and WebSocket clients with strict optional-field handling and REST beautification disabled or controlled for EXECUTION_MODE=DRY_RUN_PRIVATE, DEMO, TESTNET, or LIVE request paths.",
    "Connect private streams if credentials are present, but buffer account/order events and do not plan from socket open.",
    "Hydrate exchange info first, normalize symbol filters, and store them by product and symbol.",
    "Hydrate positions, balances, account mode, position mode, futures symbol config, and notional or leverage brackets.",
    "Hydrate regular open orders, USD-M Algo open orders, recent orders, and fills.",
    "Replace current product/symbol snapshots for open positions, regular open orders, and open Algo orders from REST hydration; keep recent history as metadata and terminal evidence, not as the current open-order set.",
    "Merge open-order hydration with recent history so current open app-owned orders and pending confirmations survive stale terminal rows for the same custom ID, preserving locally registered planned actionable fields when REST confirms the order but omits or normalizes them.",
    "Derive managed strategy side from signed position quantity in one-way USD-M mode while preserving exchange positionSide=BOTH for outbound requests.",
    "Classify app-owned orders and managed fills from order-context registry/store lookup plus trusted accountstate, including product, symbol, exchange positionSide, managed strategy side, role, step, and order kind.",
    "Plan cleanup for stale wrong-side, closed-position, wrong-kind, duplicate, or extra app-owned DCA/TP/SL orders before placing any new managed orders for the current position.",
    "Replay buffered private events, reconcile local state, and mark the product ready only after the store is coherent.",
    "Run one startup planning pass after readiness, including positions detected during hydration.",
    "If EXECUTION_MODE=DEMO, TESTNET, or LIVE is enabled, submit through the symbol-side queue, record accepted responses as pending confirmations, clear accepted client IDs from in-flight state, and wait for stream confirmation to reconcile before dependent action families.",
    "On restart, prove the startup cleanup-and-rebuild pass cancels only app-owned stale slots, rebuilds exactly one desired DCA, fixed TP, and SL set for the current position, and does not duplicate orders."
  ],
  "exchangeRuleValidation": [
    "Use Binance API docs and current package types as the authority for order fields and symbol filter names. This recipe only names the failure modes agents should look for.",
    "Parse current exchangeInfo filters into local rules for price tick, quantity step, minimum and maximum quantity, and notional constraints. Spot and USD-M expose related but not identical filter shapes.",
    "Never let a EXECUTION_MODE=DRY_RUN_PRIVATE, DEMO, TESTNET, or LIVE planner use fallback filters after REST hydration succeeded. Missing filters should create a visible planning block, syncRequired, or recoveryRequired state, not a silent guess.",
    "Quantize price and quantity from stored filters, then validate the quantized request against risk geometry, min/max quantity, price bands, and notional rules before submission. Block only when the quantized values violate those rules.",
    "For quantity-multiplier DCA, calculate the minimum usable multiplier from the current position and step size: minimumMultiplier = stepSize / positionQuantity.",
    "When a filter blocks an intent, log the exchange rule that blocked it and the raw and quantized values used to make the decision."
  ],
  "eventHandling": [
    "Do not infer product or event type from a stringified whole event object. Use typed fields and verified paths first: wsMarket, wsKey, eventType, ORDER_TRADE_UPDATE order.clientOrderId/order.symbol/order.positionSide, ALGO_UPDATE algoOrder.clientAlgoId/algoOrder.symbol/algoOrder.positionSide, TRADE_LITE clientOrderId/symbol, ACCOUNT_UPDATE updateData.updatedPositions[], order status, and execution type.",
    "Do not process the same user-data event through both formattedUserDataMessage and formattedMessage unless the project derives and checks a stable dedupe key.",
    "Missing required paths for a pending confirmation must enter scoped recovery; they must not create unidentified slot mutations or wrong-side cleanup.",
    "A safe logger can still try JSON.stringify for debugging, but it must catch failures and fall back to a small selected-field summary.",
    "Treat SDK event objects as potentially circular, large, or transport-enriched. The trading path should consume normalized event fields, not serialized blobs.",
    "Treat user-data [wsKey values](https://siebly.io/reference/glossary#ws-key) as sensitive even if they are not named listenKey."
  ],
  "replacementPhasing": [
    "If a plan contains app-owned cancels and placements for the same symbol-side workflow, submit the cleanup action first.",
    "Record accepted cancels as pending coordination state, not trusted open-order state. Treat -2011 Unknown order as terminal and benign only when private terminal proof exists or current REST open-order/open-Algo hydration proves the app-owned order is absent.",
    "In healthy private-stream mode, wait for private user-data confirmation and replan from stream-fed accountstate before placing replacement slots.",
    "Use REST hydration between cancel and place only for startup, reconnect, sync-required, exception, rejected/unknown, or conflicting-state recovery.",
    "Only submit placement intents after the old app-owned orders are gone, stale, or otherwise terminal in trusted local state.",
    "Do not place a new close-position SL in the same reconciliation pass as a cancel for the old close-position SL; Binance can reject it while the old conditional is still visible."
  ],
  "syncRecovery": [
    "If the project-local state layer reports readyToTrade=false, sync_required, or outstanding syncRequests for positions, openOrders, openAlgoOrders, balances, or fills, block planning and EXECUTION_MODE=DEMO, TESTNET, or LIVE submission.",
    "Satisfy the requested subjects with scoped REST hydration for the affected product and symbol instead of waiting for a reconnect-only path.",
    "Apply positions, regular open orders, open Algo orders, balances, and fills through the same adapter path used at startup so replacement-view semantics remain consistent.",
    "After sync recovery completes, schedule a normal product reconciliation pass rather than submitting from inside the recovery helper.",
    "Log account_sync_recovery_requested and account_sync_recovery_complete with requested subjects, hydrated counts, remaining requests, and readiness."
  ],
  "recoveryState": {
    "recoveryRequired": true,
    "operatorPaused": false,
    "blocksNewExposure": true,
    "blocksNormalPhasesUntilHydrated": true,
    "requiresScopedHydration": true,
    "clearsBy": [
      "scoped_rest_hydration",
      "buffered_user_data_replay",
      "coherent_accountstate_read"
    ]
  },
  "recoverableErrors": [
    {
      "code": "-2011",
      "name": "unknown_order_on_cancel",
      "action": "If private terminal proof already exists, or fresh REST open-order/open-Algo hydration does not contain the app-owned cancel target, treat the cancel as a benign stale-target race, mark it terminal/stale, clear in-flight state, log at info level, and do not retry forever."
    },
    {
      "code": "-2021",
      "name": "order_would_immediately_trigger",
      "action": "Treat as a recoverable placement skip for that intent, log trigger context, enter recoveryRequired or replan the affected product, and do not crash the long-running service."
    },
    {
      "code": "-4130",
      "name": "close_position_order_already_exists",
      "action": "Treat as a recoverable close-position conflict: stop the active placement action, cancel conflicting app-owned conditionals, then wait for private-stream convergence or scoped recovery hydration before replanning."
    },
    {
      "code": "-2027",
      "name": "max_position_or_leverage_limit",
      "action": "Treat as a DCA risk-limit outcome. Block or cool down the DCA slot only; keep protective TP/SL management active."
    },
    {
      "code": "-4116",
      "name": "duplicate_client_order_id",
      "action": "Treat as a pending-confirmation or conflicting-state signal, not proof of open order state. Stop the affected action family, keep duplicate-place protection active, and reconcile without product-wide pause."
    },
    {
      "code": "-5027",
      "name": "no_need_to_change",
      "action": "Apply to amend only. If current trusted accountstate still has the target slot and it is equivalent to desired, treat as converged/no-op. If accountstate does not show equivalence, run scoped recovery. Do not apply this to place or cancel."
    },
    {
      "code": "-4509",
      "name": "max_leverage_or_risk_limit",
      "action": "Treat as a DCA/risk-limit outcome when tied to exposure increase. Block or cool down DCA only and keep protective TP/SL management active."
    }
  ],
  "firstRunLogTaxonomy": {
    "startup": [
      "startup_attribution",
      "config_loaded",
      "source_verification_complete",
      "public_filters_hydrated",
      "private_stream_subscribe_requested",
      "account_backfill_complete",
      "service_ready"
    ],
    "stream": [
      "private_ws_event_received",
      "accountstate_event_applied",
      "affected_scope_recorded",
      "symbol_side_reconcile_started",
      "action_family_selected",
      "submission_accepted_pending_confirmation",
      "private_ws_confirmation_applied",
      "workflow_reconcile_complete"
    ],
    "planner": [
      "planner_finished",
      "planner_intent_blocked",
      "managed_order_replacement_summary"
    ],
    "workflow": [
      "action_family_selected",
      "cancel_action_submitted",
      "post_cancel_settle_replan_scheduled",
      "live_intent_skipped_by_guard",
      "submission_accepted_pending_confirmation",
      "private_ws_confirmation_applied",
      "workflow_reconcile_complete"
    ],
    "recovery": [
      "account_sync_recovery_requested",
      "account_sync_recovery_complete",
      "binance_submission_failed",
      "recovery_required",
      "operator_paused"
    ],
    "healthyPatterns": [
      "planner_finished intentCount=N blockedCount=0 followed by workflow_reconcile_complete submitted=N",
      "a later planner_finished intentCount=0 after pending confirmations are confirmed by private stream evidence or scoped recovery hydration"
    ],
    "attentionPatterns": [
      "readiness=sync_required",
      "planner_intent_blocked role=RISK",
      "binance_submission_failed",
      "activeOrders alternating without convergence",
      "the same custom ID repeatedly skipped or rejected"
    ]
  },
  "liveReadinessMarkerGate": {
    "markerFile": ".runtime/verified.json",
    "requiredBooleans": [
      "sdkSurfaceCheckPassed",
      "buildPassed",
      "testsPassed",
      "criticalConformancePassed"
    ],
    "rule": "When enabled, the optional runtime verification marker proves build, tests, and critical conformance for this source tree. Current execution-mode acknowledgement stays runtime config authority."
  },
  "diagnosticIntent": [
    "Startup logs should show that non-zero positions were found, REST hydration finished, and the first planner run happened after readiness.",
    "Clean live startup logs should show startup reconciliation, semantic private WS/accountstate logs, protective SL/TP action, pending confirmations, a later DCA action after confirmation, planner intentCount=0, and already-drained user-data-only deferrals skipped.",
    "Restart diagnostics should make duplicate prevention visible: existing regular orders, existing Algo orders, detected positions, intent count, blocked count, and in-flight client ID count are enough to explain the outcome.",
    "Healthy restart logs should make cleanup-and-rebuild explicit, including appOwnedCleanupPlanned counts, rebuild slot roles, and a follow-up planner_finished event with zero intents.",
    "Manual same-side add logs should show previous and hydrated quantity/average entry, desired-versus-active managed order mismatches, replacement counts, and the next planner pass at intentCount=0.",
    "Failure-pattern logs should make stale-history churn or duplicate client ID rejection visible without exposing request secrets.",
    "Unhealthy churn logs should make repeated nonzero replacement intents, client-ID drift, or metadata-only changes visible when no position fields changed.",
    "Full-close logs should show cleanup settling, no matching position, no active app-owned orders for the closed scope, and managed-slot state cleared before a fresh same-symbol same-side position is managed.",
    "Shutdown logs should show readiness, buffered event count, counts for filters, positions, orders, and fills, compact positions, and compact active app-owned orders. Do not dump full filter caches or raw payloads on signal handling.",
    "Use separate log counters for raw exchange position rows and non-zero managed positions, for example rawPositionRows and openManagedPositions.",
    "Filter blocks should explain why an order was not sent, especially the exchange filter name or local rule, raw and quantized price, raw and quantized quantity, step size, tick size, minimum quantity, minimum notional, calculated notional, role, step, and client ID.",
    "Accepted DEMO, TESTNET, or LIVE submissions should show pending confirmation state, sanitized request diff/context, and that the accepted client ID left the in-flight set.",
    "Redaction should preserve operational counters such as intentCount, blockedCount, activeOrders, positions, bufferedEventCount, and readiness while sanitizing secrets, raw request bodies, and raw [order intent](https://siebly.io/reference/glossary#order-intent) payloads."
  ],
  "restartRecoveryMatrix": [
    {
      "case": "Startup with existing position and no app-owned orders",
      "hydratedInputs": "Position exists; no app-owned regular or Algo orders are open.",
      "expectedLocalState": "Position is managed in dry-run/read-only mode with no owned order blockers.",
      "expectedPlanner": "Planner may emit dry-run DCA regular LIMIT, fixed TP regular LIMIT, and SL Algo STOP_MARKET intents after readiness.",
      "noTouchRule": "Manual or unowned orders remain untouched."
    },
    {
      "case": "Startup wipe-and-rebuild with app-owned slots",
      "hydratedInputs": "A non-zero position exists and app-owned regular DCA/TP plus Algo SL orders are open for the same scope.",
      "expectedLocalState": "Orders are recognized as app-owned slot state, then cleanup is planned before a fresh rebuild from the trusted position snapshot.",
      "expectedPlanner": "Cancels only app-owned managed orders, rebuilds one DCA, one fixed TP, and one SL if still required, and settles to intentCount=0 after private stream or scoped recovery confirmation.",
      "noTouchRule": "Manual or unowned DCA/TP/SL-like orders are never cancelled by default."
    },
    {
      "case": "Stale historical order row",
      "hydratedInputs": "Current open-order hydration shows an active app-owned order and recent history has an older terminal row for the same ID.",
      "expectedLocalState": "The current open row or pending confirmation wins over older terminal history until private stream or scoped recovery proves otherwise.",
      "expectedPlanner": "No churn and no duplicate DCA/TP/SL submission.",
      "noTouchRule": "Conflicting manual orders are not modified."
    },
    {
      "case": "Manual same-side position add",
      "hydratedInputs": "The same product, symbol, and side remains open, but REST reports larger quantity and a new weighted average entry.",
      "expectedLocalState": "The same simple scope remains active, desired DCA/TP/SL fields are recomputed from current hydrated state, and opposite hedge-side orders remain attached to their own scope.",
      "expectedPlanner": "Classify only app-owned orders whose normalized quantity, price, trigger, or exit fields changed; amend where supported, use cancel/place only for non-amendable or identity-changing slots, then settle with intentCount=0.",
      "noTouchRule": "Do not cancel unowned manual orders or opposite hedge-side app-owned orders."
    },
    {
      "case": "Full close cleanup",
      "hydratedInputs": "Position size is zero and app-owned DCA, TP, or SL orders remain open.",
      "expectedLocalState": "Managed scope is closing or closed.",
      "expectedPlanner": "Cancel or mark app-owned DCA, TP, and SL orders for cleanup according to configured shutdown/cleanup policy.",
      "noTouchRule": "Never cancel unowned manual orders."
    },
    {
      "case": "Full close cleanup settled",
      "hydratedInputs": "Position size is zero and trusted account state shows no active app-owned DCA, TP, or SL orders for the scope.",
      "expectedLocalState": "Clear managed-slot state so a later same-symbol same-side managed position starts from a fresh slot set.",
      "expectedPlanner": "No cleanup, placement, or replacement intent remains for the old scope.",
      "noTouchRule": "Do not clear an opposite hedge-side scope."
    },
    {
      "case": "One-way USD-M short",
      "hydratedInputs": "Position row has positionSide=BOTH and a negative positionAmt.",
      "expectedLocalState": "Exchange positionSide remains BOTH, managed strategy side is SHORT, and app-owned order metadata stores both values.",
      "expectedPlanner": "DCA add intents use SELL above entry, and TP/SL exit intents use BUY.",
      "noTouchRule": "Do not treat BOTH as LONG and do not change manual orders."
    },
    {
      "case": "Stale wrong-side cleanup before placement",
      "hydratedInputs": "Old app-owned short-side DCA/TP/SL orders are open, then hydration shows a new long position.",
      "expectedLocalState": "Old orders are stale by managed side or closed scope.",
      "expectedPlanner": "Emit stale app-owned cleanup intents before any new long-side placement intents.",
      "noTouchRule": "Unowned manual orders remain untouched."
    },
    {
      "case": "Unknown stale cancel",
      "hydratedInputs": "An old app-owned close-position Algo order is absent from open Algo hydration and cancel returns -2011 Unknown order.",
      "expectedLocalState": "The order is terminal or already absent from the exchange open-order view.",
      "expectedPlanner": "Mark the cancel target stale/terminal and do not retry forever.",
      "noTouchRule": "Do not escalate to cancelling unowned orders."
    },
    {
      "case": "Hedge-mode fixed TP and Algo SL",
      "hydratedInputs": "Position mode is hedge and managed positionSide is LONG or SHORT.",
      "expectedLocalState": "Outbound TP/SL requests use the matching exchange positionSide.",
      "expectedPlanner": "Fixed TP and DCA use regular LIMIT orders. A DCA LIMIT may fill immediately at limit-or-better or rest at the submitted limit price; both are normal LIMIT behavior. Do not add maker-only, post-only, mark-price, quote-freshness, marketability, or forced-maker gates unless explicitly configured. TP uses reduce-only semantics where valid; SL is an Algo STOP_MARKET close-position slot with reduceOnly omitted when closePosition=true.",
      "noTouchRule": "Do not apply one-way BOTH side inference to hedge rows."
    },
    {
      "case": "Hedge same-symbol coexistence",
      "hydratedInputs": "Existing app-owned LONG DCA/TP/SL are open and a new same-symbol SHORT position appears in hedge mode.",
      "expectedLocalState": "LONG and SHORT use independent scopes keyed by product, symbol, exchange positionSide, and managed side.",
      "expectedPlanner": "Create missing SHORT DCA/TP/SL without cancelling or replacing current LONG app-owned orders.",
      "noTouchRule": "Do not run cleanup keyed only by symbol."
    }
  ],
  "stateMachine": [
    {
      "state": "config_loaded",
      "allowedAction": "Validate config, product scope, dry-run defaults, and credentials.",
      "forbiddenAction": "No planner, cancel, amend, or LIVE submit."
    },
    {
      "state": "stream_requested",
      "allowedAction": "Request private streams and install SDK lifecycle handlers.",
      "forbiddenAction": "Do not treat the helper call as readiness."
    },
    {
      "state": "transport_open",
      "allowedAction": "Buffer private events and watch SDK reconnecting/reconnected/exception events.",
      "forbiddenAction": "Do not plan or submit from socket open alone."
    },
    {
      "state": "hydrating",
      "allowedAction": "REST hydrate positions, open orders, Algo orders, fills, filters, and modes.",
      "forbiddenAction": "No DEMO, TESTNET, or LIVE submission or cleanup cancels."
    },
    {
      "state": "replaying_buffered_events",
      "allowedAction": "Replay buffered user-data events under the workflow owner and record affected symbol-side scopes.",
      "forbiddenAction": "No overlapping reconciliation, planning, or submission pass."
    },
    {
      "state": "ready",
      "allowedAction": "Planning is allowed if risk gates pass and filters are trusted.",
      "forbiddenAction": "Do not use stale snapshots or fallback filters."
    },
    {
      "state": "planning",
      "allowedAction": "Converge desired app-owned slots against active app-owned orders by actionable slot fields and emit cleanup before placement.",
      "forbiddenAction": "Do not cancel unowned or opposite hedge-side orders."
    },
    {
      "state": "submitting",
      "allowedAction": "Record accepted responses as pending confirmations; on deterministic rejection block/surface the failed slot, and on unknown outcome enter scoped recovery.",
      "forbiddenAction": "Do not continue submitting after rejection or while recoveryRequired, syncRequired, or operatorPaused."
    },
    {
      "state": "recoveryRequired",
      "allowedAction": "Read-only diagnostics, scoped REST hydration, buffered replay, and recovery replans before normal cleanup, protection, or DCA actions resume.",
      "forbiddenAction": "No new exposure or blind retry."
    },
    {
      "state": "reconnecting",
      "allowedAction": "Enter recoveryRequired on SDK reconnecting or exception events.",
      "forbiddenAction": "Do not enter this state only because private account-event traffic is quiet."
    },
    {
      "state": "reconciling_after_reconnect",
      "allowedAction": "REST hydrate and replay buffered events after SDK reconnected.",
      "forbiddenAction": "Do not trust pre-reconnect state for new submissions."
    },
    {
      "state": "stopping",
      "allowedAction": "Close streams, flush compact summaries, and enforce a bounded shutdown timeout.",
      "forbiddenAction": "Do not dump raw payloads or cancel unowned orders."
    }
  ],
  "doNotDo": [
    "Do not process private events from both formattedMessage and formattedUserDataMessage without a tested dedupe key.",
    "Do not plan with fallback filters when hydration did not produce real symbol rules; enter recovery or block the affected slot instead.",
    "Do not send undefined optional request fields.",
    "Do not reuse a canceled client ID as the replacement client ID in the same submit action.",
    "Do not cancel manual orders unless manual-order takeover is explicitly enabled.",
    "Do not implement the default fixed TP slot as a USD-M Algo order. Fixed TP and DCA use regular LIMIT orders. A DCA LIMIT may fill immediately at limit-or-better or rest at the submitted limit price; both are normal LIMIT behavior. Do not add maker-only, post-only, mark-price, quote-freshness, marketability, or forced-maker gates unless explicitly configured. Use conditional TP only when the user explicitly requested it and the selected product supports it.",
    "Do not use TAKE_PROFIT_LIMIT for current USD-M Algo conditional TP unless the installed package types and Binance docs support it.",
    "Do not include quantity or reduceOnly with closePosition=true unless current docs say that field mix is valid.",
    "Do not treat WebSocket open as manager readiness.",
    "Do not implement run-once order management for private exchange-state managers.",
    "Do not let user-data confirmations start a competing planner while reconciliation, replay, planning, or submission is active.",
    "Do not run a full REST reconciliation for an already-drained user_data_* deferral when the event buffer is empty.",
    "Do not pause Binance order management only because no private account event arrived recently while the SDK transport is healthy.",
    "Do not log full hydrated exchange filters, full in-memory stores, or raw payload caches during signal shutdown.",
    "Do not treat USD-M positionSide=BOTH as the managed strategy side; infer one-way LONG or SHORT from signed positionAmt.",
    "Do not leave app-owned DCA orders open after full position close or position flip, because they can reopen exposure.",
    "Do not leave stale managed-slot state attached after full-close cleanup has settled with no matching position and no active app-owned orders.",
    "Do not suppress replacement just because role and step match when actionable slot fields for that order kind changed.",
    "Do not clean or replace opposite hedge-side app-owned orders just because they share the same symbol.",
    "Do not retry -2011 Unknown order cancels forever when the app-owned order is absent from current REST open-order hydration.",
    "Do not send reduceOnly on hedge-mode USD-M Algo SL or explicit conditional TP requests unless current docs and package types explicitly require it.",
    "Do not perform full REST hydration for every repeated idle ACCOUNT_UPDATE when a short symbol-side event-burst wait can preserve correctness.",
    "Do not let stale pending confirmations remain active forever after private stream confirmation or scoped REST recovery proves they are absent.",
    "Do not let safe diagnostic commands inherit EXECUTION_MODE=DEMO, TESTNET, or LIVE from .env.",
    "Do not redact operational counters such as intentCount or activeOrders just because their names contain words like intent or order."
  ],
  "fixtureCases": [
    {
      "name": "Existing USD-M position with no app-owned orders",
      "purpose": "Proves startup hydration feeds the planner after readiness.",
      "expected": "Planner emits dry-run DCA, TP, and SL intents, using hydrated filters and product-specific position state."
    },
    {
      "name": "Existing position with one app-owned DCA order",
      "purpose": "Proves restart ownership classification prevents duplicate DCA.",
      "expected": "Planner does not create another DCA for the same product, symbol, side, and step."
    },
    {
      "name": "Startup wipe-and-rebuild with existing app-owned slots",
      "purpose": "Proves restart recovery does not attempt to recover lifecycle or generation from Binance client IDs.",
      "expected": "Planner cancels only app-owned managed slots for the hydrated scope, preserves unowned manual orders, rebuilds fixed TP as regular LIMIT, SL as Algo STOP_MARKET, and settles to intentCount=0."
    },
    {
      "name": "Restart with active app-owned order and stale terminal history",
      "purpose": "Proves current open-order hydration wins over older history rows for the same app-owned ID.",
      "expected": "Planner emits no duplicate DCA/TP/SL and no cancel/replacement churn."
    },
    {
      "name": "Fixed TP uses regular LIMIT",
      "purpose": "Proves the ordinary take-profit slot uses regular LIMIT semantics and is not implemented through Algo conditionals.",
      "expected": "TP uses submitNewOrder with type=LIMIT, timeInForce=GTC, newClientOrderId, and reduce-only semantics where valid for the account mode; no maker-only, post-only, mark-price, quote-freshness, or marketability gates are added unless explicitly configured."
    },
    {
      "name": "Client ID drift does not replace slot",
      "purpose": "Proves exchange-visible ID metadata is not part of desired-vs-active equality for the default manager once ownership and slot identity are established.",
      "expected": "A role/step-equivalent active order with matching normalized request fields is kept even if the regenerated client ID string would differ."
    },
    {
      "name": "Step-size or minimum-notional filter block",
      "purpose": "Proves exchange filters are wired into the planner, not merely fetched.",
      "expected": "A small DCA notional whose quantized values violate step size or minimum notional is blocked locally with an exchange-filter reason instead of being submitted."
    },
    {
      "name": "Cancelled historical app-owned order",
      "purpose": "Proves historical metadata does not block restart restoration after an operator cancels orders externally.",
      "expected": "Cancelled, expired, rejected, and filled historical orders are retained for metadata but do not count as active blockers once trusted open-order state and pending confirmations are current."
    },
    {
      "name": "User-data cancel while DEMO, TESTNET, or LIVE submission is active",
      "purpose": "Proves private events cannot trigger a second overlapping symbol-side workflow pass.",
      "expected": "The event is buffered or marked for symbol-side replanning, and the active workflow finishes or aborts before another reconciliation or plan runs."
    },
    {
      "name": "User-data confirmation during deferred reconciliation",
      "purpose": "Proves own-order NEW confirmations do not start a competing planner while deferred REST reconciliation is active.",
      "expected": "The event is deferred at info level, replayed by the active workflow pass, and the deferred planner emits intentCount=0."
    },
    {
      "name": "Already-replayed user-data deferral",
      "purpose": "Proves redundant user-data replans are skipped after the buffer was drained by a just-completed workflow pass.",
      "expected": "When bufferedEventCount is zero and every deferred reason starts with user_data_, the deferred replan is skipped without REST reconciliation or planning."
    },
    {
      "name": "USD-M Algo update",
      "purpose": "Proves formatted Algo order updates reconcile app-owned exits.",
      "expected": "The update is classified from typed fields and updates only the matching app-owned TP/SL state."
    },
    {
      "name": "Full position close cleanup",
      "purpose": "Proves app-owned DCA and exits are removed after the managed position is gone.",
      "expected": "Remaining app-owned DCA, TP, and SL orders are cancelled or marked for cleanup without touching unowned manual orders."
    },
    {
      "name": "Full close clears managed-slot state after cleanup settled",
      "purpose": "Proves in-memory managed slot state does not survive a complete close and cleanup.",
      "expected": "When trusted account state shows no matching position and no active app-owned orders for the scope, slot state is cleared and the next same-symbol same-side position starts fresh."
    },
    {
      "name": "Fresh same-symbol same-side open after cleanup",
      "purpose": "Proves historical orders and fills from a previous manually closed position do not pollute a fresh position.",
      "expected": "The fresh position starts from current hydrated position or account-state evidence and old closed-scope app-owned metadata is not reused for placements."
    },
    {
      "name": "Manual same-side add slot classification",
      "purpose": "Proves operator-added size on the same product, symbol, and side updates managed order fields without changing unrelated scope identity.",
      "expected": "The planner classifies each app-owned slot as keep, amend, cancel_place, cancel, or place, uses amendment where the current Binance surface supports it, uses cancel/place only for non-amendable or identity-changing slots, then settles with intentCount=0 after hydration."
    },
    {
      "name": "One-way USD-M short from BOTH positionSide",
      "purpose": "Proves positionSide=BOTH plus negative positionAmt becomes managed strategy side SHORT.",
      "expected": "The planner stores exchange positionSide=BOTH, managed side SHORT, DCA SELL above entry, and TP/SL BUY exits."
    },
    {
      "name": "Stale wrong-side cleanup before placement",
      "purpose": "Proves a position flip cannot leave old app-owned orders live while new orders are placed.",
      "expected": "Old short-side app-owned DCA/TP/SL cleanup intents are emitted before any new long-side placement intents."
    },
    {
      "name": "Position flip stale unknown Algo cancel",
      "purpose": "Proves absent close-position Algo orders do not create infinite cancel retry loops.",
      "expected": "If open Algo hydration no longer contains the app-owned order and Binance returns -2011, the order is marked terminal/stale and not retried forever."
    },
    {
      "name": "Hedge-mode USD-M Algo SL without reduceOnly",
      "purpose": "Proves hedge-mode positionSide=LONG or SHORT uses the correct Algo SL field mix.",
      "expected": "Hedge-mode close-position SL conditionals omit reduceOnly; fixed TP remains a regular order."
    },
    {
      "name": "Hedge same-symbol coexistence",
      "purpose": "Proves side-specific scope keys preserve existing orders when the opposite hedge side opens.",
      "expected": "Existing LONG app-owned orders survive while a new same-symbol SHORT receives independent DCA, TP, and SL orders."
    },
    {
      "name": "Idle ACCOUNT_UPDATE burst handling",
      "purpose": "Proves repeated private account updates do not cause one full REST hydration per event.",
      "expected": "The manager groups repeated idle account updates by affected symbol-side into a bounded reconciliation pass while startup, reconnect, and unknown submission state still reconcile immediately."
    },
    {
      "name": "Behavior-contract fixture sync",
      "purpose": "Verifies generated local tests stay aligned with the current [behavior-contract fixtures](https://siebly.io/reference/glossary#behavior-contract-fixture).",
      "expected": "Run the latest [behavior-contract fixtures](https://siebly.io/reference/glossary#behavior-contract-fixture) from the [Conformance Pack](https://siebly.io/reference/glossary#conformance-pack) plus the integration kit operatorConformanceScript. The pack covers startup wipe/rebuild, fixed TP regular LIMIT, close-position Algo SL, formatted private event paths, stream-first convergence, symbol-side action gating, pending confirmations, DCA risk blocking, same-side position add slot classification, hedge-side coexistence, redaction boundaries, and other maintained checks."
    },
    {
      "name": "Shutdown compact summary and timeout",
      "purpose": "Proves signal shutdown does not dump full filters/raw payloads and cannot hang indefinitely on WebSocket close handles.",
      "expected": "Shutdown logs compact counts, readiness, buffered event count, positions, and active app-owned orders, then exits after manager stop or a forced timeout."
    },
    {
      "name": "Stale or fallback filters",
      "purpose": "Proves the planner refuses EXECUTION_MODE=DRY_RUN_PRIVATE, DEMO, TESTNET, or LIVE orders when hydrated filters are missing or stale.",
      "expected": "The product is visibly paused or the intent is blocked with the missing filter reason."
    },
    {
      "name": "Accepted live DCA response",
      "purpose": "Proves local submission state is updated before stream confirmation.",
      "expected": "The accepted order creates a pending confirmation and its custom ID is removed from the in-flight set."
    },
    {
      "name": "Circular formatted user-data event",
      "purpose": "Proves event handling is not coupled to whole-object serialization.",
      "expected": "Product inference and reconciliation use typed fields; logging falls back to a safe summary if stringify fails."
    }
  ],
  "observability": [
    "Serialize unknown SDK/API errors as structured JSON. Do not log String(error) or template-string unknown errors.",
    "Preserve exchange code, message, HTTP status, headers, response body, sanitized request URL, sanitized request and [order intent](https://siebly.io/reference/glossary#order-intent) summaries, product, symbol, and client order ID where available.",
    "Redact secrets, API keys, signatures, listen keys, signed REST URLs, websocket URLs, websocket keys, raw request bodies, raw [order intent](https://siebly.io/reference/glossary#order-intent) payloads, SDK debug messages, and retry/reconnect logs before stdout or stderr.",
    "Do not redact operational counters such as intentCount, blockedCount, activeOrders, positions, bufferedEventCount, inFlightClientIds, or readiness.",
    "When exchange filters block an order intent, log raw and quantized price, raw and quantized quantity, tick size, step size, min quantity, max quantity, min notional, calculated notional, strategy role, step, and exact filter reason.",
    "Disable SDK REST response beautification for production trading paths, or verify all SDK logging is routed through structured redacted logging instead of raw console output."
  ],
  "knownRejections": [
    {
      "code": "-1111",
      "message": "Precision is over the maximum defined for this asset",
      "fix": "Treat this as a symptom of local rule validation missing or using stale/fallback filters. Re-read the current symbol filters, quantize with tick size and step size, then block only requests whose quantized price, quantity, or notional still violates exchange rules before submission."
    },
    {
      "code": "-4116",
      "message": "ClientOrderId is duplicated",
      "fix": "Treat this as duplicate custom ID submission, missing context registration, or missing reconciliation. Track in-flight IDs, record pending confirmations, and reconcile before retrying."
    },
    {
      "code": "-1116",
      "message": "Invalid orderType",
      "fix": "For the default fixed take-profit slot, use a regular LIMIT order instead of Algo. Only explicit conditional TP uses USD-M Algo, and then the current type enum must be verified instead of inventing strategy-language values such as TAKE_PROFIT_LIMIT."
    },
    {
      "code": "-1106",
      "message": "Parameter 'reduceonly' sent when not required",
      "fix": "When closePosition=true is used for a USD-M close-position conditional, omit reduceOnly from the request. In hedge mode with positionSide=LONG or SHORT, omit reduceOnly from USD-M Algo SL or explicit conditional TP requests unless current docs and package types explicitly say otherwise."
    },
    {
      "code": "-2011",
      "message": "Unknown order sent",
      "fix": "Treat this as a stale or terminal app-owned order when current open-order or open-Algo hydration no longer contains the order. Mark it terminal/stale, stop retrying the cancel, and reconcile before planning replacements."
    },
    {
      "code": "-2013",
      "message": "Order does not exist",
      "fix": "For cancel/amend, treat as benign only with proof: private terminal evidence for the same target, or scoped REST absence after refresh. If REST shows the target present, replan; if REST is inconclusive, keep recoveryRequired."
    },
    {
      "code": "-5027",
      "message": "No need to modify",
      "fix": "Amend-only no-op. Treat as converged only when trusted accountstate shows the current active slot is already equivalent on actionable fields. Do not apply this to place/cancel, and run scoped recovery if equivalence is unknown."
    },
    {
      "code": "-5029",
      "message": "Notional below minimum",
      "fix": "Classify as deterministic filter_block. For regular TP limit, omit or block desired TP and cancel stale infeasible TP where appropriate. For regular DCA limit, block DCA with an explicit min-notional reason. Do not blindly apply TP/DCA behavior to Algo SL."
    },
    {
      "code": "-2027",
      "message": "Maximum allowable position exceeded",
      "fix": "For DCA place, block or cool the DCA slot without marking accountstate untrusted or pausing protective TP/SL management."
    },
    {
      "code": "-2019",
      "message": "Insufficient margin",
      "fix": "For DCA place, block insufficient_margin and delete any prepared context for the rejected place. Recheck only after position, balance, or cooldown state changes."
    }
  ],
  "localScaffold": [
    ".env.example plus automatic .env loading in every normal local entrypoint using Node.js built-in env-file support, process.loadEnvFile, dotenv/config, or the existing repo env loader",
    "documented environment precedence: real process env overrides .env",
    "public or read-only startup that can run without EXECUTION_MODE=LIVE permission",
    "EXECUTION_MODE=DRY_RUN_PRIVATE startup with scoped credentials",
    "explicit EXECUTION_MODE=execution acknowledgement gate",
    "Node.js LTS TypeScript settings compatible with the repo runtime",
    "strict optional request field handling that omits undefined values",
    "build, lint, test, and dry-run commands in README",
    "documented supported values for every environment variable, config option, EXECUTION_MODE value, and execution acknowledgement string",
    "JSON config override examples with defaults and per-symbol override shape",
    "[Safe commands](https://siebly.io/reference/glossary#safe-command) such as doctor, inspect, status, and readback must force EXECUTION_MODE=PUBLIC or READ_ONLY_PRIVATE even if the environment contains EXECUTION_MODE=DEMO, TESTNET, or LIVE."
  ],
  "safety": [
    "Use EXECUTION_MODE=DRY_RUN_PRIVATE for order-capable local runs.",
    "Treat the manager as a long-running service. Run-once order management cannot reconcile fills, cancels, reconnects, or full-close cleanup.",
    "Exchange writes require EXECUTION_MODE=LIVE plus explicit user configuration, scoped credentials, reviewed code, conformance, [risk gates](https://siebly.io/reference/glossary#risk-gate), and manual acknowledgement.",
    "Never cancel or amend unowned manual orders unless manual-order takeover is explicitly enabled.",
    "Separate Spot and USD-M product state, position side, filters, account modes, and risk gates.",
    "Default to one pending DCA step at a time unless the operator explicitly enables a full pre-placed DCA ladder.",
    "Managed [Custom Order IDs](https://siebly.io/reference/glossary#custom-order-id) are context lookup keys for the default manager; lifecycle/generation IDs are an advanced opt-in persistent design, not the default.",
    "Do not allow a second reconciliation, replay, planning, or submission pass to run while the workflow owner is active.",
    "User-data confirmations from app-owned submissions are normal; defer them at info level while a workflow is active, then reconcile before any planner run.",
    "If bufferedEventCount is zero and every deferred reason starts with user_data_, skip the already-replayed deferral instead of spending REST weight.",
    "App-owned DCA/TP/SL orders must be reconciled after DCA fills and removed after full position close or position flip; unowned manual orders remain untouched unless takeover is explicitly enabled.",
    "One-way USD-M side handling separates exchange positionSide=BOTH from managed strategy side LONG or SHORT inferred from signed position quantity.",
    "REST open-order hydration is the recovery view for active exchange orders. Stale app-owned cancel targets absent from that view must not be retried forever after -2011.",
    "[Safe commands](https://siebly.io/reference/glossary#safe-command) such as doctor, inspect, status, and readback must force EXECUTION_MODE=PUBLIC or READ_ONLY_PRIVATE even if the environment contains EXECUTION_MODE=DEMO, TESTNET, or LIVE.",
    "Redacted logs keep operational counters visible while hiding secrets, raw requests, and raw [order intent](https://siebly.io/reference/glossary#order-intent) payloads.",
    "Shutdown logs stay compact and bounded: counts, readiness, buffered event count, compact positions, compact active app-owned orders, and a timeout around incomplete stop/close paths."
  ],
  "promptFrameworkCompletionWorkflow": {
    "instruction": "Recursive completion workflow:\n1. Before implementation, save this exact prompt in docs/AI_PROMPT.md (or docs/SPEC.md when that is the project standard) and write docs/PLAN.md with phases, invariants, tests or fixtures, docs to update, and acceptance gates.\n2. Review docs/PLAN.md for missing workflows, unsafe assumptions, product/exchange-specific leakage, unclear state ownership, confirmation or recovery gaps, missing tests, and incomplete docs. Update docs/PLAN.md and repeat until one full review pass finds no actionable changes.\n3. Implement one plan phase at a time. After each phase, review changed code, tests, fixtures, docs, generated artifacts, and runtime workflows against docs/PLAN.md and this prompt. Fix gaps and repeat until that phase has no actionable changes before starting the next phase.\n4. After all phases, run a full-depth project review across every workflow, lifecycle, state transition, error path, and artifact. This is not a shallow summary pass. Fix every actionable gap and repeat until a full pass finds no further changes, then record the final review outcome in docs/PLAN.md.",
    "acceptanceRequirement": "docs/PLAN.md records the initial plan, plan-review iterations, phase review outcomes, final full-project review, validation commands, and any documented non-claims. No plan phase or project completion is accepted until the recursive review loop finds no actionable gaps, flaws, or incomplete workflows left to correct."
  }
}
