{
  "format": "siebly-integration-kit/v1",
  "id": "binance-position-manager",
  "title": "Binance Position Management Integration Kit",
  "lastReviewed": "2026-05-12",
  "package": {
    "ecosystem": "npm",
    "name": "binance",
    "install": "npm install binance",
    "versionPolicy": "Use the latest available binance package in the generated project. Record the installed version in the README dependency notes; do not pin implementation guidance to a version observed in one prior test run.",
    "docs": "https://siebly.io/sdk/binance/javascript",
    "repository": "https://github.com/tiagosiebler/binance"
  },
  "agentImplementationManifest": "https://siebly.io/.well-known/agent-manifests/binance-position-manager/latest.json",
  "conformancePack": "https://siebly.io/.well-known/conformance/binance-position-manager/latest.json",
  "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."
  },
  "artifactOrder": [
    "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"
  ],
  "spec": [
    "Install the latest available SDK and verify exact method/type names from installed declarations.",
    "Build a formatted private-event field-path matrix for ORDER_TRADE_UPDATE, ALGO_UPDATE, TRADE_LITE, and ACCOUNT_UPDATE from installed declarations before private event routing.",
    "Store the exact generated prompt and a machine-readable prompt manifest before implementation so future audits can compare implementation behavior with the original instructions.",
    "Use the simple managed-slot lane unless the user explicitly asks for a persistent advanced strategy.",
    "Implement Binance [Custom Order IDs](https://siebly.io/reference/glossary#custom-order-id) as order-context lookup keys only.",
    "Hydrate filters, positions, regular open orders, open Algo orders, recent orders/fills, account mode, position mode, and leverage/notional constraints.",
    "Store hydrated filters; never plan EXECUTION_MODE=DRY_RUN_PRIVATE, DEMO, TESTNET, or LIVE orders from fallback filters.",
    "On startup, reconnect, or recovery, cancel open app-owned managed orders before rebuilding slots from current positions.",
    "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 Algo STOP_MARKET close-position orders for SL where supported by the selected product.",
    "Implement the event-driven private-state loop (ws_symbol_side_action_gated). Private events update [Account State](https://siebly.io/reference/glossary#accountstate), record the [affected scope](https://siebly.io/reference/glossary#affected-scope), give related events a short bounded window to arrive, and one [workflow owner](https://siebly.io/reference/glossary#workflow-owner) chooses one [action family](https://siebly.io/reference/glossary#action-family). Accepted mutations stay [pending confirmation](https://siebly.io/reference/glossary#pending-confirmation) until [private confirmation](https://siebly.io/reference/glossary#private-stream-confirmation) or [scoped recovery](https://siebly.io/reference/glossary#scoped-recovery), and REST state fetches happen only at trust boundaries.",
    "Implement slot convergence normalizers, including regular TP/DCA LIMIT field matching and USD-M Algo close-position SL default echo handling.",
    "Implement one workflow owner with symbol-side affected work items. 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.",
    "Do not enter REST recovery just because private order, execution, fill, or position events arrived. If the private stream is healthy and [Account State](https://siebly.io/reference/glossary#accountstate) has ingested the matching order evidence plus the matching position or account evidence, continue from private-stream account state without REST hydration. For products without exchange-provided position rows, locally derived position evidence fills the same role.",
    "Implement private user-data supervision: typed classification, buffering, short event-burst waiting, and immediate recovery precedence for reconnect/exception/rejection events.",
    "Pre-register order context and preflight each DEMO, TESTNET, or LIVE intent before its exchange request; do not let duplicate-place guards block cleanup cancels. Fresh protective SL/TP may dispatch as concurrent separate orders by default.",
    "Treat Binance -2027 as DCA risk-limited/cooldown while protective TP/SL management continues.",
    "After implementation, run the applicable [behavior-contract fixtures](https://siebly.io/reference/glossary#behavior-contract-fixture) from the [Conformance Pack](https://siebly.io/reference/glossary#conformance-pack) before enabling EXECUTION_MODE=DEMO, TESTNET, or LIVE order submission. [conformance packs](https://siebly.io/reference/glossary#conformance-pack) are the machine-readable fixture sources for these checks."
  ],
  "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."
  ],
  "managerLane": "simple managed slots",
  "authorityOrder": [
    "User behavior goal and safety requirements.",
    "Official exchange docs for order semantics.",
    "Installed SDK TypeScript declarations for method names and request shapes.",
    "accountstate or project-local account-state docs for state ingestion and readiness.",
    "Siebly recipes, manifests, integration kits, and [behavior-contract fixtures](https://siebly.io/reference/glossary#behavior-contract-fixture) for scaffolding and known pitfalls."
  ],
  "behaviorContract": {
    "architecture": "ws_symbol_side_action_gated",
    "reusableArchitecture": "order_account_position_state_machine",
    "reusablePrimitives": [
      "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"
    ],
    "managerLane": "simple_managed_slots",
    "accountStateSource": "Use the account-state layer as the in-memory account view. Feed it startup REST snapshots and private account events. Local submission outcomes are provisional coordination evidence and pending-confirmation inputs, not trusted open-order state. Do not build a second account-state reducer.",
    "subjectTrust": "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.",
    "nativePositionReplanning": "For products with exchange-provided position rows, private order/fill updates are triggers, not replacement authority. Wait for the matching position or account-state update before re-protecting, re-DCA, cleanup/noop decisions, or run scoped recovery if the stream is broken.",
    "localPositionStateForNonNativeProducts": "For products without exchange-provided position rows, define local position state from fills/executions, fees, account events, balance updates, and documented matching rules. Do not apply derivative position lifecycle rules silently to balances alone.",
    "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.",
    "defaultStrategyConfig": "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.",
    "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.",
    "slotIdentity": "Use deterministic internal SlotKey values for strategy identity. Custom order IDs are lookup keys into an order-context store. Treat ID drift as non-actionable when role, step, side, quantity, price, trigger, exit semantics, and order kind still match.",
    "customOrderIdRegistry": "[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.",
    "startupRecovery": "On startup, reconnect, restart, or recovery, hydrate trusted state first, manage orders proven app-owned by the runtime or persisted order store, optionally clean unknown scoped orders only when explicit config enables it, then rebuild expected slots from current positions.",
    "healthyStream": "During normal private event bursts, apply every event to [Account State](https://siebly.io/reference/glossary#accountstate) immediately, then use a short [event-burst wait](https://siebly.io/reference/glossary#event-burst-wait) before planning. Do not enter REST recovery just because private order, execution, fill, or position events arrived. If the private stream is healthy and [Account State](https://siebly.io/reference/glossary#accountstate) has ingested the matching order evidence plus the matching position or account evidence, continue from private-stream account state without REST hydration. For products without exchange-provided position rows, locally derived position evidence fills the same role.",
    "restBoundary": "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.",
    "actionFamilyGate": "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. Normal cleanup, protection, and DCA work must not run from stale or unresolved state. Recovering uncertain state means blocking normal action families, running scoped hydration and buffered replay until local state is coherent with exchange state, then requeueing the [affected scope](https://siebly.io/reference/glossary#affected-scope).",
    "protectiveDispatch": "For fresh protection, pre-register SL and TP contexts and dispatch the separate SL and TP orders concurrently by default. If serialized protective mode is configured, submit SL before TP. DCA remains gated until required protection is trusted.",
    "pendingConfirmations": "Accepted place/amend/cancel responses create [pending confirmations](https://siebly.io/reference/glossary#pending-confirmation) and duplicate-submit protection, but they do not unlock dependent action families until [private confirmation](https://siebly.io/reference/glossary#private-stream-confirmation) or [scoped recovery](https://siebly.io/reference/glossary#scoped-recovery) proves account state.",
    "submissionTimeout": "Use a configurable bounded confirmation timeout for unknown REST/WS outcomes; 5 seconds is a reasonable default for generated managers before scoped recovery. Unknown outcomes enter scoped recovery rather than duplicate submit or trusted success.",
    "slotConvergence": "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. Regular fixed-price TP and DCA LIMIT slots converge by slot identity, order side, quantity, and limit price after tick/lot normalization. Close-position or close-on-trigger SL slots converge by slot identity, order side, trigger price, trigger source, close-position semantics, and stop kind; hydrated quantity, price, reduce-only, and default false-like fields are diagnostic unless current exchange docs make them actionable. Exchange echo fields, generated order IDs, lifecycle counters, default booleans, omitted trigger-only fields on regular orders, and display-only precision differences must not trigger cancel/recreate churn.",
    "liveRunFailureFixtures": "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.",
    "semanticWsLogs": "Emit semantic logs for private stream ingestion and account-state application: 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.",
    "advancedLane": "Durable lifecycle epochs, replacement generations, and cross-process adoption belong to an advanced persistent strategy lane only when explicitly requested and tested.",
    "identityChainAcceptance": "Do not mark the implementation complete until three consecutive full identity-chain review passes produce no code, tests, fixtures, or documentation changes."
  },
  "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."
    ]
  },
  "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."
    ]
  },
  "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."
  ],
  "forbiddenDesigns": [
    "Keep product, symbol, role, side, step, order kind, lifecycle, generation, recovery state, and other strategy state out of the ID text.",
    "Do not recover strategy meaning from exchange-visible IDs after restart for the default manager.",
    "Do not add a generic custom-ID prefix unless the exchange or SDK requires one.",
    "Do not use conditional/Algo/trigger orders for ordinary fixed-price TP targets unless that behavior is explicitly configured and supported.",
    "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.",
    "Do not use REST hydration as the normal reaction to healthy private account events, healthy order/fill/position events, or ordinary pending confirmations.",
    "Do not replace all slots because one slot changed.",
    "Do not replace any slot solely because a client ID, lifecycle counter, generation value, or in-memory metadata changed.",
    "Do not pause protective TP/SL management because an exposure-increasing DCA order hit max-position, leverage, notional, or equivalent risk limits.",
    "Do not compare raw hydrated order objects field-by-field; compare managed slots by the actionable fields for that order kind.",
    "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.",
    "Do not submit protective exits and exposure-increasing DCA in the same first workflow pass for a newly discovered position.",
    "Do not let accepted submit responses unlock dependent action families until the private stream or scoped recovery hydration confirms account state."
  ],
  "promptProvenance": {
    "files": [
      "docs/AI_PROMPT.md",
      "docs/AI_PROMPT_MANIFEST.json"
    ],
    "manifestRequiredFields": [
      "createdFrom",
      "generatedAt",
      "exchange",
      "products",
      "selectedFeatures",
      "permissionBoundary",
      "linkedArtifacts",
      "installedPackages",
      "liveGateNames",
      "criticalFixtureNames"
    ],
    "rule": "Commit the exact prompt text and selected prompt options before implementation so prompt coverage can be compared with implementation behavior."
  },
  "criticalWriteConformance": {
    "mustPassBeforeLive": [
      "startup_wipe_rebuild_cancels_app_orders_before_rebuild",
      "position_open_reacts_without_timer",
      "position_open_places_protective_then_dca_after_ws_confirmation",
      "accepted_submissions_settle_to_zero_intents",
      "fixed_tp_uses_regular_limit",
      "sl_is_algo_stop_market_close_position",
      "one_way_tp_sends_reduce_only_regular_limit",
      "hedge_regular_tp_omits_reduce_only_but_ignores_hydrated_echo",
      "usdm_algo_close_position_hydration_defaults",
      "client_id_change_alone_does_not_replace_order",
      "only_changed_slot_replaced",
      "same_side_position_add_classifies_slots_once",
      "healthy_user_data_reconcile_skips_rest_backfill",
      "semantic_ws_logs_emitted_after_ingest",
      "symbol_side_queue_groups_private_event_burst",
      "private_stream_event_during_active_workflow_defers_followup",
      "pending_confirmation_does_not_unlock_dependent_action_family",
      "pending_confirmations_do_not_trigger_replacement",
      "pending_place_guard_does_not_block_cancel",
      "custom_order_id_registry_lookup_routes_private_event",
      "binance_formatted_order_trade_update_uses_order_client_order_id",
      "binance_formatted_algo_update_uses_algo_order_client_algo_id",
      "binance_formatted_trade_lite_routes_by_registry_or_broad_scope",
      "binance_formatted_account_update_position_rows_create_position_trust",
      "binance_formatted_event_missing_required_path_enters_recovery",
      "binance_terminal_private_proof_makes_2011_cancel_benign",
      "protective_sl_tp_pre_registered_and_dispatched_concurrently_by_default",
      "unknown_submit_outcome_enters_recovery_after_configured_timeout",
      "recovery_required_blocks_normal_actions_until_hydration_succeeds",
      "duplicate_client_id_4116_enters_recovery_without_pause",
      "amend_no_need_to_change_treated_converged_when_current_slot_equivalent",
      "max_leverage_4509_blocks_dca_only",
      "account_sync_required_triggers_scoped_rest_hydration",
      "recoverable_immediate_trigger_does_not_crash_service",
      "close_position_conflict_replans_after_cancel_settle",
      "dca_2027_blocks_dca_only",
      "dca_2019_blocks_dca_only",
      "regular_tp_dca_5029_filter_block_is_role_specific",
      "live_submission_exception_clears_inflight",
      "unknown_order_cancel_absent_from_hydration_marks_terminal",
      "private_stream_exception_fails_startup",
      "live_marker_required_before_live_start",
      "hedge_same_symbol_opposite_side_coexists",
      "position_full_close_cleans_app_orders",
      "binary_float_tails_are_formatted_from_filters",
      "websocket_beautify_required_for_formatted_user_data",
      "rest_beautify_disabled_for_accountstate_inputs",
      "custom_oid_guard_preflights_before_submit",
      "cancel_before_place_replacement_converges_before_place",
      "deferred_replan_reentrant_calls_are_grouped",
      "full_close_cleanup_clears_slot_state_after_cleanup_settles",
      "binary_float_precision_tails_are_formatted",
      "fallback_filters_block_live_planning"
    ],
    "conformancePack": "https://siebly.io/.well-known/conformance/binance-position-manager/latest.json",
    "requiredOutcome": "Create local behavior-contract tests from the [Conformance Pack](https://siebly.io/reference/glossary#conformance-pack) and keep EXECUTION_MODE=DEMO, TESTNET, or LIVE submission unavailable until these cases pass."
  },
  "sdkSurfaceChecklist": [
    "Before coding, save the exact generated prompt to docs/AI_PROMPT.md (or docs/SPEC.md when that is the project standard) and selected prompt options to docs/AI_PROMPT_MANIFEST.json.",
    "Install the latest available binance package and record the installed version in the README dependency notes.",
    "Start from the agent manifest and integration kit, then record applicable [Behavior-Contract Fixture](https://siebly.io/reference/glossary#behavior-contract-fixture) coverage before editing exchange code.",
    "Inspect installed TypeScript declarations and package exports for the methods and types below; use SDK docs, endpoint maps, and examples only to resolve unclear request shapes.",
    "Verify regular USD-M order docs/types for fixed TP and DCA, and verify the USD-M Algo Orders guide only for SL, trailing stops, or explicitly requested conditional TP.",
    "Verify formatted private-event paths for ORDER_TRADE_UPDATE, ALGO_UPDATE, TRADE_LITE, and ACCOUNT_UPDATE, including the nested client ID and position-row paths used by the event router.",
    "Write SDK surface notes in the generated README or docs with exact methods, types, and files checked."
  ],
  "minimalImplementationPath": [
    "Persist prompt provenance files, then install dependencies.",
    "Install the latest SDK, inspect installed declarations, and record SDK surface notes in the README before implementation.",
    "Scaffold config, EXECUTION_MODE=DRY_RUN_PRIVATE store, SDK-prefixed [Custom Order ID](https://siebly.io/reference/glossary#custom-order-id) helpers, order-context registry, filter parsing, planner, submitter, and structured logging with the write-capable [EXECUTION_MODE](https://siebly.io/reference/glossary#execution-mode) values DEMO, TESTNET, and LIVE disabled by default.",
    "Implement REST hydration, replacement-view snapshots, private stream buffering, replay, and the gated DEMO, TESTNET, or LIVE submission path.",
    "Add explicit EXECUTION_MODE=DEMO, TESTNET, or LIVE submission gates, pending confirmations, in-flight ID tracking, and rejection recoveryRequired/reconcile behavior.",
    "Add [behavior-contract fixtures](https://siebly.io/reference/glossary#behavior-contract-fixture) for startup wipe-and-rebuild, fixed TP regular LIMIT, formatted private event paths, external cancel recovery, same-side position add slot classification, full close cleanup, hedge side coexistence, stale pending confirmations, symbol-side action gating, safe doctor/status commands, and redaction boundaries."
  ],
  "stateStoreBoundary": {
    "installPolicy": "Implement the state store locally by default. Use a published state package only when the user explicitly chooses one and the generated project verifies its exports, imports, adapters, and package contents first.",
    "sdkSurfaceCheckTargets": [
      "project-local replacement snapshots for positions, regular open orders, open Algo orders, balances, fills, and configured risk state",
      "project-local private event adapter that feeds the same state boundary used by REST hydration",
      "managed order parser, desired-slot-to-NormalizedOrder conversion, and normalized comparison policies",
      "submission error classifier and unknown-order helper",
      "readyToTrade, trust flags, and syncRequests behavior if the generated project exposes them"
    ],
    "safety": "Do not copy dependency llms or package metadata into generated docs without secret scanning for .npmrc, _authToken, API keys, or private registry credentials."
  },
  "sdkSurfaceCheckScriptShape": {
    "filename": "scripts/verify-binance-position-manager-surfaces.mjs",
    "command": "node scripts/verify-binance-position-manager-surfaces.mjs",
    "scriptLines": [
      "import fs from 'node:fs';",
      "import path from 'node:path';",
      "import { createRequire } from 'node:module';",
      "",
      "const require = createRequire(import.meta.url);",
      "const packageJsonPath = require.resolve('binance/package.json');",
      "const packageRoot = path.dirname(packageJsonPath);",
      "const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));",
      "const sdk = await import('binance');",
      "",
      "const requiredExports = [",
      "  'MainClient',",
      "  'USDMClient',",
      "  'WebsocketClient',",
      "  'generateNewOrderId',",
      "  'getOrderIdPrefix',",
      "];",
      "",
      "const missingExports = requiredExports.filter((name) => !(name in sdk));",
      "const declarationTargets = [",
      "  'RestClientOptions',",
      "  'WSClientConfigurableOptions.beautify',",
      "  'RestClientOptions.beautifyResponses',",
      "  'FuturesNewOrderParams',",
      "  'FuturesNewAlgoOrderParams',",
      "  'FuturesAlgoConditionalOrderTypes',",
      "  'FuturesAlgoOrderResponse',",
      "  'formattedUserDataMessage',",
      "  'WsMessageFuturesUserDataAccountUpdateFormatted.updateData.updatedPositions',",
      "  'WsMessageFuturesUserDataTradeUpdateEventFormatted.order.clientOrderId',",
      "  'WsMessageFuturesUserDataTradeLiteEventFormatted.clientOrderId',",
      "  'WsMessageFuturesUserDataAlgoUpdateFormatted.algoOrder.clientAlgoId',",
      "  'isWsFormattedFuturesUserDataAccountUpdate',",
      "  'isWsFormattedFuturesUserDataTradeUpdateEvent',",
      "  'isWsFormattedFuturesAlgoUpdateEvent',",
      "  'BEAUTIFIER_EVENT_MAP ACCOUNT_UPDATEEvent ORDER_TRADE_UPDATEEvent TRADE_LITEEvent ALGO_UPDATEEvent',",
      "  'subscribeSpotUserDataStream',",
      "  'subscribeUsdFuturesUserDataStream',",
      "  'closeAll',",
      "];",
      "",
      "const report = {",
      "  package: 'binance',",
      "  installedVersion: packageJson.version,",
      "  packageRoot,",
      "  ok: missingExports.length === 0,",
      "  exports: Object.fromEntries(requiredExports.map((name) => [name, name in sdk])),",
      "  missingExports,",
      "  declarationTargetsToInspect: declarationTargets,",
      "  formattedPrivateEventFieldMatrix: {",
      "    ORDER_TRADE_UPDATE: ['order.clientOrderId', 'order.symbol', 'order.positionSide', 'order.executionType', 'order.orderStatus'],",
      "    ALGO_UPDATE: ['algoOrder.clientAlgoId', 'algoOrder.symbol', 'algoOrder.positionSide', 'algoOrder.orderType', 'algoOrder.algoStatus'],",
      "    TRADE_LITE: ['clientOrderId', 'symbol', 'side', 'lastFilledPrice', 'lastFilledQuantity'],",
      "    ACCOUNT_UPDATE: ['updateData.updatedPositions[].symbol', 'updateData.updatedPositions[].positionSide', 'updateData.updatedPositions[].positionAmount', 'updateData.updatedPositions[].entryPrice'],",
      "  },",
      "  nextStep:",
      "    'Open installed package declarations and confirm REST raw/beautify options, WebSocket beautify=true for formatted private events, USD-M regular and Algo literals, formatted private event field paths, WebSocket event names, closeAll signature, and optional-field behavior before coding.',",
      "};",
      "",
      "console.log(JSON.stringify(report, null, 2));",
      "if (!report.ok) process.exit(1);"
    ],
    "reportMustInclude": [
      "installed binance version",
      "missing package exports",
      "package root",
      "declaration targets inspected before coding",
      "valid USD-M Algo type literals from installed declarations",
      "WebSocket event names and closeAll signature",
      "order ID prefix utility availability",
      "formatted private event field matrix inspected"
    ]
  },
  "canonicalSources": [
    "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/llms.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"
  ],
  "sdkSurface": {
    "restClients": [
      "MainClient",
      "USDMClient"
    ],
    "websocketClient": "WebsocketClient",
    "privateStreamHelpers": [
      "subscribeSpotUserDataStream",
      "subscribeUsdFuturesUserDataStream"
    ],
    "websocketEvents": [
      "open",
      "response",
      "formattedMessage",
      "formattedUserDataMessage",
      "reconnecting",
      "reconnected",
      "exception"
    ],
    "shutdown": "closeAll(true) or current documented closeAll variant",
    "spotRest": [
      "getExchangeInfo",
      "getAccountInformation",
      "getOpenOrders",
      "getAllOrders",
      "getAccountTradeList",
      "submitNewOrder",
      "cancelOrder",
      "testNewOrder"
    ],
    "usdmRest": [
      "getExchangeInfo",
      "getPositionsV3",
      "getAllOpenOrders",
      "getOpenAlgoOrders",
      "getAccountTrades",
      "getAllOrders",
      "getAccountInformationV3",
      "getCurrentPositionMode",
      "getMultiAssetsMode",
      "getFuturesSymbolConfig",
      "getNotionalAndLeverageBrackets",
      "submitNewOrder",
      "cancelOrder",
      "testOrder",
      "submitNewAlgoOrder",
      "cancelAlgoOrder"
    ],
    "customClientIdFields": {
      "spotAndUsdmRegular": "newClientOrderId",
      "usdmAlgoConditional": "clientAlgoId"
    },
    "formattedPrivateEventTypes": [
      "WsMessageFuturesUserDataAccountUpdateFormatted",
      "WsMessageFuturesUserDataTradeUpdateEventFormatted",
      "WsMessageFuturesUserDataTradeLiteEventFormatted",
      "WsMessageFuturesUserDataAlgoUpdateFormatted"
    ]
  },
  "installedPackageLookupMap": [
    {
      "surface": "REST clients",
      "lookupTargets": [
        "MainClient",
        "USDMClient"
      ],
      "verify": "Find the public client declarations and confirm account, position, open-order, Algo, submit, cancel, and test-order methods before coding."
    },
    {
      "surface": "USD-M Algo request type",
      "lookupTargets": [
        "FuturesNewAlgoOrderParams",
        "FuturesAlgoConditionalOrderTypes",
        "FuturesAlgoOrderResponse"
      ],
      "verify": "Confirm current fields and valid type literals for TAKE_PROFIT, STOP_MARKET, closePosition, reduceOnly, positionSide, workingType, and priceProtect."
    },
    {
      "surface": "Private WebSocket lifecycle",
      "lookupTargets": [
        "WebsocketClient",
        "formattedUserDataMessage",
        "formattedMessage",
        "reconnected",
        "exception",
        "closeAll"
      ],
      "verify": "Confirm private stream helper names, event names, reconnect events, and shutdown method from installed declarations."
    },
    {
      "surface": "Formatted private user-data field paths",
      "lookupTargets": [
        "WsMessageFuturesUserDataAccountUpdateFormatted.updateData.updatedPositions",
        "WsMessageFuturesUserDataTradeUpdateEventFormatted.order.clientOrderId",
        "WsMessageFuturesUserDataTradeLiteEventFormatted.clientOrderId",
        "WsMessageFuturesUserDataAlgoUpdateFormatted.algoOrder.clientAlgoId",
        "BEAUTIFIER_EVENT_MAP"
      ],
      "verify": "Confirm exact formatted paths before implementing the adapter; root newClientOrderId/clientAlgoId guesses are not valid for formatted USD-M ORDER_TRADE_UPDATE or ALGO_UPDATE."
    },
    {
      "surface": "REST client options and order ID utilities",
      "lookupTargets": [
        "RestClientOptions",
        "filterUndefinedParams",
        "strictParamValidation",
        "beautifyResponses",
        "getOrderIdPrefix",
        "generateNewOrderId"
      ],
      "verify": "Confirm undefined-field filtering, strict validation, response beautification controls, and SDK-prefix order ID utilities."
    }
  ],
  "requestFieldMatrix": [
    {
      "mode": "USD-M one-way LONG",
      "hydratedPosition": "positionSide=BOTH and signed positionAmt > 0",
      "managedStrategySide": "LONG",
      "outboundPositionSide": "BOTH",
      "dcaAddSide": "BUY below entry",
      "takeProfitSide": "SELL above entry",
      "stopLossSide": "SELL below entry",
      "fixedTakeProfit": "Regular LIMIT SELL above entry with newClientOrderId; reduceOnly=true in one-way mode when current docs/types allow it.",
      "algoReduceOnly": "Algo path is for close-position SL or explicit conditional TP only; omit reduceOnly when closePosition=true."
    },
    {
      "mode": "USD-M one-way SHORT",
      "hydratedPosition": "positionSide=BOTH and signed positionAmt < 0",
      "managedStrategySide": "SHORT",
      "outboundPositionSide": "BOTH",
      "dcaAddSide": "SELL above entry",
      "takeProfitSide": "BUY below entry",
      "stopLossSide": "BUY above entry",
      "fixedTakeProfit": "Regular LIMIT BUY below entry with newClientOrderId; reduceOnly=true in one-way mode when current docs/types allow it.",
      "algoReduceOnly": "Algo path is for close-position SL or explicit conditional TP only; omit reduceOnly when closePosition=true."
    },
    {
      "mode": "USD-M hedge LONG",
      "hydratedPosition": "positionSide=LONG",
      "managedStrategySide": "LONG",
      "outboundPositionSide": "LONG",
      "dcaAddSide": "BUY below entry",
      "takeProfitSide": "SELL above entry",
      "stopLossSide": "SELL below entry",
      "fixedTakeProfit": "Regular LIMIT SELL above entry with newClientOrderId; omit reduceOnly in hedge mode if current Binance rules reject it.",
      "algoReduceOnly": "Omit reduceOnly from close-position Algo SL and explicit conditional TP requests."
    },
    {
      "mode": "USD-M hedge SHORT",
      "hydratedPosition": "positionSide=SHORT",
      "managedStrategySide": "SHORT",
      "outboundPositionSide": "SHORT",
      "dcaAddSide": "SELL above entry",
      "takeProfitSide": "BUY below entry",
      "stopLossSide": "BUY above entry",
      "fixedTakeProfit": "Regular LIMIT BUY below entry with newClientOrderId; omit reduceOnly in hedge mode if current Binance rules reject it.",
      "algoReduceOnly": "Omit reduceOnly from close-position Algo SL and explicit conditional TP requests."
    },
    {
      "mode": "close-position stop-market",
      "fields": "type=STOP_MARKET, closePosition=true, triggerPrice, workingType, priceProtect, clientAlgoId, side, positionSide",
      "forbiddenFields": [
        "quantity",
        "reduceOnly"
      ]
    },
    {
      "mode": "fixed take-profit regular limit",
      "fields": "type=LIMIT, quantity, price, timeInForce=GTC, newClientOrderId, side, positionSide, reduceOnly only where current account mode/docs allow it",
      "forbiddenFields": [
        "clientAlgoId",
        "triggerPrice",
        "closePosition",
        "workingType",
        "priceProtect"
      ]
    },
    {
      "mode": "explicit conditional take-profit",
      "fields": "type=TAKE_PROFIT, quantity, price, triggerPrice, timeInForce=GTC, workingType, priceProtect, clientAlgoId, side, positionSide",
      "oneWayReduceOnly": "May include reduceOnly=true in one-way BOTH only when configured and locally validated.",
      "hedgeReduceOnly": "Omit reduceOnly for hedge-mode LONG or SHORT Algo conditionals.",
      "useOnlyWhen": "The user explicitly requested conditional TP behavior. Do not use this for the default fixed TP slot."
    }
  ],
  "eventReconciliationPolicy": {
    "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."
      ]
    },
    "recoveryAuthority": "REST startup, reconnect, exception, sync-required, submission-recovery, and conflicting-state hydration are the recovery source of truth; private user-data events are the live update stream after readiness.",
    "replacementViews": [
      "positions",
      "regularOpenOrders",
      "algoOpenOrders"
    ],
    "workflowLock": "One workflow owner covers REST reconciliation, buffered user-data replay, planning, and EXECUTION_MODE=DEMO, TESTNET, or LIVE submission with symbol-side affected work items.",
    "activeWorkflowUserData": "Buffer user_data_* replans while the workflow lock is held; expected own-order NEW confirmations are info logs.",
    "idleUserData": "Replay private events into trusted accountstate before planning. Emit semantic private WS/accountstate logs and, for ACCOUNT_UPDATE-only clusters, wait 750ms-1500ms per affected symbol-side with a 3000ms max delay so related events can arrive before planning; use REST only when syncRequired, recoveryRequired, reconnect, exception, rejection, unknown state, or conflicting state demands it.",
    "immediateUserDataEvents": "ORDER_TRADE_UPDATE, TRADE_LITE, executionReport, ALGO_UPDATE, listenKeyExpired, fills, cancels, and rejects reconcile immediately.",
    "skipAlreadyReplayed": "Skip only when bufferedEventCount === 0 and every deferred reason starts with user_data_.",
    "immediateReconciliationTriggers": [
      "startup",
      "SDK reconnecting, reconnected, or exception lifecycle event",
      "live rejection",
      "unknown submission state",
      "conflicting REST/history/user-data state"
    ],
    "streamHealth": "Do not infer Binance user-data stream failure from ordinary account-event idleness while the SDK transport remains healthy. Use SDK lifecycle events as the stream-health authority: enter recoveryRequired on reconnecting or exception, then REST hydrate and replay buffered events on reconnected before resuming new exposure."
  },
  "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"
    ]
  },
  "privateStreamStartupReadiness": {
    "rules": [
      "Attach exception, open, reconnecting, and reconnected handlers before subscribing.",
      "Do not treat subscribe helper completion as application readiness.",
      "For private streams, SDK exception is authoritative stream-health failure.",
      "After subscribing, inspect product readiness or a supervisor failure flag.",
      "Required live startup gate: stream requested, transport open, REST hydration complete, no required product has recoveryRequired from exception, buffered replay complete.",
      "Do not emit service_ready while any required private-stream product has recoveryRequired or syncRequired from SDK exception."
    ],
    "snippet": "ws.on('exception', (event) => supervisor.onException(event));\nws.on('open', (event) => supervisor.onOpen(event));\nws.on('reconnecting', (event) => supervisor.onReconnecting(event));\nws.on('reconnected', (event) => supervisor.onReconnected(event));\n\nawait adapter.connectPrivateStreams();\n\nconst failed = products.filter((product) => store.getTradingState(product).recoveryRequired);\nif (failed.length > 0) {\n  throw new Error(`Private stream startup failed for products: ${failed.join(',')}`);\n}\n\nawait hydrateAllEnabledProducts();\nawait replayBufferedEvents();\nlogger.info('service_ready', { products });",
    "failureInvariant": "A required private product with recoveryRequired from SDK exception prevents service_ready and EXECUTION_MODE=DEMO, TESTNET, or LIVE submission, even if a subscribe helper awaited without throwing."
  },
  "goldenConvergenceTrace": [
    "startup -> stream_requested -> REST hydrate openManagedPositions=0 regularOpenOrders=0 openAlgoOrders=0 -> planner intentCount=0",
    "position open -> formatted user-data ORDER_TRADE_UPDATE -> private_ws_event_received -> accountstate_event_applied -> affected_scope_recorded",
    "replay private events into accountstate, or scoped REST hydrate only at a trust boundary, then action_family_selected protective with roles SL,TP",
    "submit SL Algo STOP_MARKET and fixed TP regular LIMIT; each accepted response creates pending confirmation state",
    "own-order user-data confirmations are deferred while the workflow is active",
    "private confirmations or scoped recovery hydration show one regular and one Algo app-owned protective order -> action_family_selected dca",
    "submit one pending DCA regular LIMIT and record pending confirmation",
    "private confirmations or scoped recovery hydration show regularOpenOrders=2 and openAlgoOrders=1 -> planner intentCount=0 activeOrders=3"
  ],
  "workflowLockRules": [
    "The workflow owner is acquired once for reconcile -> replay -> plan -> submit, then processes one affected symbol-side item at a time.",
    "Submission runs inside the active workflow and must not reacquire the same lock.",
    "Never submit protective exits and DCA in the same first workflow pass for a new position.",
    "An empty intent action skips submission cleanly without recording workflow_already_active or deferred submission reasons.",
    "Private user-data events received while the lock is held buffer and set deferred reasons for the next reconciliation pass.",
    "Only the caller that actually entered the workflow owns after-active follow-up scheduling; reentrant callers should record bounded defer reasons without scheduling log storms."
  ],
  "liveIntentPreflightRules": [
    "Filter blocked intents before EXECUTION_MODE=DEMO, TESTNET, or LIVE submission.",
    "Pre-register order context and preflight every remaining cancel, amend, and place intent before its exchange call.",
    "Block duplicate place requests while a pending confirmation exists for the same slot; do not block cleanup cancels for that same app-owned ID.",
    "Block duplicate custom IDs and in-flight custom IDs before submission.",
    "Normal exposure-increasing, replacement, and DCA work is confirmation-gated; fresh protective SL/TP may dispatch concurrently as separate orders by default after both contexts are registered.",
    "Every accepted place, amend, or cancel response creates a pending confirmation and sanitized accepted-submission log.",
    "Pending confirmations suppress duplicate submissions but do not unlock DCA or later replacement actions until private stream evidence or scoped recovery hydration confirms the outcome.",
    "Every accept, reject, and throw path clears the in-flight client ID in a finally-equivalent path.",
    "A -2011 cancel for an app-owned order with private terminal proof or absent from fresh open-order hydration is a benign stale-target race: log at info, mark the order terminal or stale, and do not leave its client ID stuck in flight."
  ],
  "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."
  ],
  "liveIntentPreflightSnippet": "async function submitActionFamilyInsideWorkflow(intents) {\n  const submitIntents = intents.filter((intent) => !intent.blocked);\n  if (submitIntents.length === 0) {\n    logger.info('submission_action_skipped_empty', { intentCount: 0 });\n    return;\n  }\n\n  for (const intent of submitIntents) {\n    orderContextStore.set(intent.clientId, {\n      slotKey: intent.slotKey,\n      role: intent.role,\n      actionFamily: intent.actionFamily,\n      request: summarizeRequest(intent),\n      submittedAt: Date.now(),\n    });\n    if (intent.action === 'place' && pendingConfirmations.has(intent.slotKey)) {\n      throw enterRecoveryRequired('pending_confirmation_guard', { slotKey: intent.slotKey });\n    }\n    if (inFlight.has(intent.clientId)) {\n      throw enterRecoveryRequired('duplicate_or_inflight_client_id', { clientId: intent.clientId });\n    }\n  }\n\n  const canDispatchConcurrently =\n    submitIntents.every((intent) => intent.actionFamily === 'protective' && ['SL', 'TP'].includes(intent.role));\n  const selectedIntents = canDispatchConcurrently ? submitIntents : submitIntents.slice(0, 1);\n\n  if (canDispatchConcurrently) {\n    logger.info('protective_dispatch_started', { intentCount: selectedIntents.length });\n  }\n\n  await Promise.all(selectedIntents.map(async (intent) => {\n    inFlight.add(intent.clientId);\n    try {\n      const response = await exchange.submit(intent);\n      pendingConfirmations.add(intent.slotKey, { intent, response });\n      logger.info('submission_accepted_pending_confirmation', {\n        slotKey: intent.slotKey,\n        role: intent.role,\n        actionFamily: intent.actionFamily,\n        requestDiff: summarizeActionableDiff(intent),\n      });\n    } catch (error) {\n      classifySubmissionFailureOrEnterRecovery(intent, error);\n      throw error;\n    } finally {\n      inFlight.delete(intent.clientId);\n    }\n  }));\n}",
  "hydrationRules": [
    "REST open positions, regular open orders, and open Algo orders replace the current product snapshot for the hydrated scope.",
    "Absent app-owned open orders are terminal or stale unless a newer user-data event proves otherwise.",
    "Accepted REST submissions are pending confirmations until confirmed by user-data or scoped recovery hydration.",
    "When REST confirms an app-owned order is open but omits or normalizes fields needed for slot convergence, preserve the locally accepted planned actionable fields for that custom ID.",
    "If later private stream confirmation or scoped REST recovery still omits a pending app-owned order after a short configured grace window, mark it stale so it cannot block replacement forever.",
    "Recent history is metadata and terminal evidence, not the active open-order view.",
    "Current open app-owned order state or pending confirmation wins over older terminal history for the same custom ID until confirmed stale.",
    "If timestamps, statuses, or identifiers conflict and cannot be resolved deterministically, enter recoveryRequired and reconcile instead of submitting."
  ],
  "desiredOrderComparisonFields": [
    "Regular fixed TP/DCA LIMIT: product, symbol, exchange positionSide, managed strategy side, role, DCA step, order side, quantity, price, and regular-order kind.",
    "Close-position Algo SL: product, symbol, exchange positionSide, managed strategy side, role, step, order side, trigger price, workingType, closePosition semantics, and Algo stop kind.",
    "Diagnostic-only after slot match unless docs make actionable: reduceOnly echo, priceProtect echo, hydrated quantity/price for close-position SL, generated order IDs, and regular-order trigger defaults."
  ],
  "desiredOrderNormalizationRules": [
    {
      "case": "Tick formatting",
      "desired": "75036.5",
      "hydrated": "75036.50",
      "equal": true,
      "rule": "Compare by tick-normalized decimal value and format output from tickSize precision."
    },
    {
      "case": "Close-position stop quantity",
      "desired": "omitted",
      "hydrated": "0.0",
      "equal": true,
      "rule": "For app-owned USD-M Algo close-position SL comparison, quantity is an exchange default after identity, side, trigger, workingType, and priceProtect match."
    },
    {
      "case": "Close-position stop price",
      "desired": "omitted",
      "hydrated": "0.0",
      "equal": true,
      "rule": "For app-owned USD-M Algo close-position SL comparison, price is an exchange default after identity, side, trigger, workingType, and priceProtect match."
    },
    {
      "case": "Close-position stop closePosition and reduceOnly defaults",
      "desired": "closePosition=true, reduceOnly omitted",
      "hydrated": "closePosition true/false/omitted and reduceOnly true/false/omitted",
      "equal": true,
      "rule": "For app-owned USD-M Algo close-position SL comparison, closePosition and reduceOnly are exchange defaults once the managed close-position SL identity and trigger fields match."
    },
    {
      "case": "Hedge close-position Algo SL reduceOnly",
      "desired": "omitted",
      "hydrated": "false or response default",
      "equal": true,
      "rule": "For hedge-mode close-position Algo SL, omit reduceOnly in requests and ignore or normalize exchange defaults during comparison."
    },
    {
      "case": "Regular DCA trigger-only fields",
      "desired": "omitted",
      "hydrated": "0, false, or exchange default",
      "equal": true,
      "rule": "Regular DCA comparison ignores triggerPrice, closePosition, workingType, and priceProtect defaults that are irrelevant to the limit order."
    }
  ],
  "usdmAlgoClosePositionHydrationDefaults": {
    "name": "usdm_algo_close_position_hydration_defaults",
    "description": "An app-owned USD-M Algo close-position STOP_MARKET SL can hydrate with exchange defaults that should not churn replacement.",
    "desired": {
      "product": "usdm",
      "kind": "algo",
      "role": "SL",
      "type": "STOP_MARKET",
      "closePosition": true,
      "quantity": null,
      "price": null,
      "reduceOnly": null,
      "triggerPrice": "99000.0",
      "positionSide": "BOTH"
    },
    "hydratedVariants": [
      {
        "quantity": "0.0",
        "price": "0.0",
        "closePosition": "true",
        "reduceOnly": "false",
        "priceProtect": "true"
      },
      {
        "quantity": "0.01",
        "price": "0.0",
        "closePosition": false,
        "reduceOnly": true,
        "priceProtect": true
      },
      {
        "quantity": null,
        "price": null,
        "closePosition": null,
        "reduceOnly": null,
        "priceProtect": null
      }
    ],
    "equivalenceRule": "After matching product, symbol, exchangePositionSide, managedStrategySide, role, step, side, triggerPrice, workingType, closePosition semantics, and Algo stop kind through registry slot context plus trusted accountstate, treat quantity, price, reduceOnly, priceProtect, clientAlgoId drift, and other echo/default fields as diagnostic unless current docs make them actionable.",
    "expect": {
      "equivalent": true,
      "intentCount": 0,
      "doNotCancel": true
    }
  },
  "orderComparisonSnippet": "import type { AccountScope, NormalizedOrder } from 'accountstate';\nimport { areBinanceManagedOrdersEquivalent } from 'accountstate/binance';\n\ntype DesiredManagedOrder = {\n  slot: {\n    symbol: string;\n    exchangePositionSide: string;\n    managedSide: 'LONG' | 'SHORT';\n    role: 'TP' | 'SL' | 'DCA';\n    step: number;\n    orderKind: 'regular_LIMIT' | 'algo_STOP_MARKET';\n  };\n  side: 'BUY' | 'SELL';\n  positionSide?: string;\n  quantity?: string;\n  price?: string;\n  triggerPrice?: string;\n  reduceOnly?: boolean;\n  closePosition?: boolean;\n  workingType?: string;\n};\n\nfunction desiredManagedOrderToNormalizedOrder(\n  scope: AccountScope,\n  desired: DesiredManagedOrder,\n  updatedAtMs = 0,\n): NormalizedOrder {\n  const isAlgoStop = desired.slot.orderKind === 'algo_STOP_MARKET';\n\n  return {\n    ...scope,\n    symbol: desired.slot.symbol,\n    kind: isAlgoStop ? 'algo' : 'regular',\n    side: desired.side,\n    type: isAlgoStop ? 'STOP_MARKET' : 'LIMIT',\n    status: 'new',\n    exchangePositionSide: desired.positionSide ?? desired.slot.exchangePositionSide,\n    strategySide: desired.slot.managedSide,\n    quantity: desired.quantity,\n    price: desired.price,\n    triggerPrice: desired.triggerPrice,\n    reduceOnly: desired.reduceOnly,\n    closePosition: desired.closePosition,\n    workingType: desired.workingType,\n    timeInForce: isAlgoStop ? undefined : 'GTC',\n    owner: 'app',\n    metadata: {\n      role: desired.slot.role,\n      step: desired.slot.step,\n      exchangePositionSide: desired.slot.exchangePositionSide,\n      strategySide: desired.slot.managedSide,\n    },\n    updatedAtMs,\n    source: 'local',\n  };\n}\n\nfunction managedOrdersEquivalent(\n  scope: AccountScope,\n  desired: DesiredManagedOrder,\n  active: NormalizedOrder,\n  positionMode: 'one-way' | 'hedge',\n) {\n  return areBinanceManagedOrdersEquivalent({\n    desired: desiredManagedOrderToNormalizedOrder(scope, desired),\n    active,\n    product: 'usdm',\n    positionMode,\n  });\n}",
  "decimalFormattingRules": [
    "Quantize with decimal-safe arithmetic or fixed-point/string helpers, not binary float stringification.",
    "Format final request price from hydrated tickSize decimal precision, for example 74992.800000000003 with tickSize 0.1 becomes 74992.8.",
    "Format final request quantity from hydrated stepSize decimal precision, for example 0.0020000000000000005 with stepSize 0.001 becomes 0.002.",
    "After formatting, reject only if the quantized quantity is zero, below step size, or below minimum notional."
  ],
  "simpleStartupRecoveryAlgorithm": [
    "For each hydrated non-zero position, derive the simple scope from product, symbol, exchangePositionSide, and managedStrategySide.",
    "Classify app-owned open orders by order-context registry/store lookup when available; after store loss, do not parse custom IDs for slot meaning.",
    "On startup, reconnect, or recoveryRequired, cancel stale or extra app-owned slots for the hydrated scope before rebuilding desired slots from the current position.",
    "Do not recover lifecycle epochs or replacement generations from Binance client IDs for the default manager.",
    "After full close cleanup completes, clear active slot state so a fresh later position is planned only from current account state."
  ],
  "placementPriority": [
    "stale app-owned cleanup",
    "protective stop-loss",
    "protective take-profit",
    "exposure-increasing DCA"
  ],
  "simpleSlotRules": [
    "App-owned order metadata stores product, symbol, exchange positionSide, managed strategy side, role, step, and order kind.",
    "Cleanup stale wrong-side, closed-position, wrong-kind, duplicate, or extra app-owned DCA/TP/SL orders before placing rebuilt slots.",
    "After full position close or position flip, clean up app-owned DCA as well as TP/SL because DCA orders can reopen exposure.",
    "If the operator manually cancels app-owned DCA/TP/SL while the position remains open and operatorPaused is false, the next reconciliation should recreate the missing managed orders.",
    "In hedge mode, LONG and SHORT on the same symbol are independent managed scopes; closing or cleaning one side must preserve the other side."
  ],
  "commandSafety": [
    "[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.",
    "Safe inspection commands should strip credentials, disable order placement/cancel/amend endpoints, and refuse to inherit execution acknowledgement flags.",
    "README command examples should make the safe mode visible so operators can run diagnostics without exchange-facing side effects."
  ],
  "redactionPolicy": {
    "redact": [
      "API keys",
      "signatures",
      "listen keys",
      "wsKey",
      "signed URLs",
      "private headers",
      "raw request bodies",
      "raw orderIntent payloads",
      "SDK debug messages that contain private request material"
    ],
    "preserveCounters": [
      "intentCount",
      "blockedCount",
      "activeOrders",
      "positions",
      "bufferedEventCount",
      "inFlightClientIds",
      "readiness"
    ],
    "rule": "Redaction should match explicit sensitive fields or paths, not broad substrings such as intent, order, or position that hide operational counters."
  },
  "structuredLoggingContract": {
    "reservedTopLevelFields": [
      "ts",
      "level",
      "event"
    ],
    "rule": "Application logger context must not overwrite reserved top-level fields. If SDK context contains event, level, or ts, preserve it under contextEvent or a nested context field.",
    "nestedErrorRule": "SDK logger context can contain nested error or exception values. Preserve nested message, code, response status, headers, and body after redaction.",
    "snippet": "function emit(level, eventName, context = {}) {\n  const { event: contextEvent, level: _level, ts: _ts, ...safeContext } = redact(context);\n  const line = {\n    ts: new Date().toISOString(),\n    level,\n    event: eventName,\n    ...safeContext,\n    ...(contextEvent === undefined ? {} : { contextEvent }),\n  };\n  console[level === 'error' ? 'error' : 'log'](JSON.stringify(line));\n}\n\nfunction serializeSdkError(error) {\n  const out = { errorType: typeof error };\n  if (error instanceof Error) {\n    out.name = error.name;\n    out.message = error.message;\n    out.stack = error.stack;\n  }\n  if (error && typeof error === 'object') {\n    out.exchangeCode = error.code;\n    out.exchangeMessage = error.msg;\n    out.message = error.message ?? out.message;\n    if (error.response) {\n      out.httpStatus = error.response.status;\n      out.responseHeaders = error.response.headers;\n      out.responseBody = error.response.data;\n    }\n    if (error.error || error.exception) {\n      out.nested = serializeSdkError(error.error ?? error.exception);\n    }\n  }\n  return redact(out);\n}"
  },
  "rejectionCatalog": [
    {
      "code": "-1111",
      "cause": "Precision is over the maximum defined for this asset",
      "localAction": "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",
      "cause": "ClientOrderId is duplicated",
      "localAction": "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",
      "cause": "Invalid orderType",
      "localAction": "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",
      "cause": "Parameter 'reduceonly' sent when not required",
      "localAction": "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",
      "cause": "Unknown order sent",
      "localAction": "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",
      "cause": "Order does not exist",
      "localAction": "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",
      "cause": "No need to modify",
      "localAction": "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",
      "cause": "Notional below minimum",
      "localAction": "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",
      "cause": "Maximum allowable position exceeded",
      "localAction": "For DCA place, block or cool the DCA slot without marking accountstate untrusted or pausing protective TP/SL management."
    },
    {
      "code": "-2019",
      "cause": "Insufficient margin",
      "localAction": "For DCA place, block insufficient_margin and delete any prepared context for the rejected place. Recheck only after position, balance, or cooldown state changes."
    }
  ],
  "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"
    ]
  },
  "fixtures": [
    "Clean startup: startup reconcile -> protective SL/TP action -> own-order user-data confirmations deferred -> DCA action after confirmation -> planner intentCount=0 -> already-drained deferrals skipped.",
    "Golden convergence: startup empty -> position open user-data updates accountstate and records the affected symbol-side scope -> protective action emits SL/TP -> pending confirmations -> DCA action after confirmation -> planner intentCount=0.",
    "Empty submit action inside active workflow: hydrate -> planner intentCount=0 -> submission skipped without workflow_already_active.",
    "User-data schedules reconcile: startup positions=0 -> ORDER_TRADE_UPDATE buffered while idle -> accountstate openManagedPositions=1 -> protective action intentCount=2.",
    "Protective order priority: new position with no orders emits placement roles SL and TP after any cleanup intents, then DCA only after confirmation.",
    "Float tail normalized from filters: price 74992.800000000003 with tickSize 0.1 formats to 74992.8; quantity 0.0020000000000000005 with stepSize 0.001 formats to 0.002, then the quantized request is revalidated before submission.",
    "Fixed TP request path: ordinary take-profit uses regular LIMIT through the regular order surface; when still open it appears in regularOpenOrders, not openAlgoOrders.",
    "Hydrated close-position Algo normalization: desired omitted quantity/price and hydrated 0.0 quantity/price compare equal for SL.",
    "Startup wipe-and-rebuild: app-owned managed slots are cancelled and rebuilt from trusted account state without recovering lifecycle from client IDs.",
    "Manual full close: position size is zero and app-owned DCA/TP/SL remain; cleanup app-owned orders only.",
    "Full close slot clearing: after trusted state confirms no matching position and no active app-owned orders for the scope, clear in-memory slot state so a later same-symbol same-side position starts fresh.",
    "Two separate position lifecycles on same symbol and side: the second starts from current account state and does not inherit stale orders/fills from the first.",
    "One-way short: positionSide=BOTH plus negative positionAmt becomes managed strategy side SHORT while outbound requests still send positionSide=BOTH.",
    "Stale wrong-side cleanup: old short-side app-owned DCA/TP/SL exist, hydration shows long position, cleanup emits before new long placement.",
    "Position flip stale unknown Algo cancel: app-owned close-position Algo is absent from open Algo hydration and -2011 does not retry forever.",
    "Hedge-mode TP/SL: positionSide=LONG or SHORT conditionals omit reduceOnly; one-way BOTH fixture covers configured quantity-based reduceOnly.",
    "Hedge coexistence: existing LONG app-owned DCA/TP/SL survives while a new same-symbol SHORT scope gets its own DCA/TP/SL.",
    "Manual same-side add: account state reports larger size and new weighted average entry; planner classifies only that side/scope orders whose desired fields changed and the next reconciliation settles at intentCount=0.",
    "Idle ACCOUNT_UPDATE storm: repeated account updates wait 750ms-1500ms per affected symbol-side with a 3000ms max delay so related events can arrive before planning, without skipping startup, reconnect, order/fill/algo, reject, cancel, or unknown-state hydration.",
    "Manual cancel recovery: app-owned DCA/TP/SL are manually cancelled while the position remains open; next reconciliation recreates the missing managed orders unless operatorPaused is true.",
    "Pending confirmation staleness: accepted REST response created pending confirmation state, but private stream or scoped recovery omits it after the grace window; local state marks it stale and allows replacement.",
    "Safe doctor/status command: .env may contain EXECUTION_MODE=LIVE, but the command forces EXECUTION_MODE=PUBLIC or READ_ONLY_PRIVATE and cannot place, cancel, or amend orders.",
    "Redaction boundary: raw request/[order intent](https://siebly.io/reference/glossary#order-intent) fields are sanitized while intentCount, blockedCount, activeOrders, and positions remain visible.",
    "Filter precision handling: hydrated filters quantize locally, then invalid quantized values are blocked before Binance returns -1111.",
    "Duplicate client ID: accepted response creates pending confirmation state and clears in-flight ID before stream confirmation; cleanup cancels are not blocked by pending place IDs.",
    "Custom ID preflight: duplicate or in-flight custom ID fails before the exchange call.",
    "Private stream startup exception: SDK exception sets recoveryRequired for the required product and prevents service_ready.",
    "DCA risk block: -2027 blocks or cools down only the DCA slot while TP/SL management remains active.",
    "Deferred replan grouping: same-side add produces one slot-update action and one follow-up convergence pass without reentrant log storms."
  ],
  "conformancePackFixtures": "https://siebly.io/.well-known/conformance/binance-position-manager/latest.json",
  "conformanceFixtures": [
    {
      "name": "accepted_submissions_settle_to_zero_intents",
      "given": "openManagedPositions=1, openRegularOrders has one app-owned DCA, openAlgoOrders has app-owned SL and TP, filters are hydrated",
      "expect": "intentCount=0, activeOrders=3, no cancel or place intents"
    },
    {
      "name": "binance_precision_float_tail_quantized_from_filters",
      "given": "raw price 74992.800000000003 tickSize 0.1 and raw quantity 0.0020000000000000005 stepSize 0.001",
      "expect": "formatted price 74992.8, formatted quantity 0.002, no Binance -1111 submission"
    },
    {
      "name": "startup_wipe_rebuild_cancels_app_orders_before_rebuild",
      "given": "same product/symbol/exchangePositionSide/managedStrategySide has existing app-owned DCA, TP, and SL open at startup",
      "expect": "cleanup cancels app-owned managed slots before rebuild, unowned manual orders are untouched, and rebuilt slots settle to intentCount=0"
    },
    {
      "name": "fixed_tp_uses_regular_limit",
      "given": "new USD-M managed position needs a fixed take-profit",
      "expect": "TP is submitted via submitNewOrder LIMIT with newClientOrderId and is tracked through the regular order surface, not openAlgoOrders"
    },
    {
      "name": "workflow_active_user_data_defers_replan",
      "given": "own-order user-data confirmation arrives while submit action is inside active symbol-side workflow",
      "expect": "event buffered, reason deferred at info level, next reconciliation settles to intentCount=0"
    },
    {
      "name": "protective_orders_before_dca",
      "given": "new managed position with no app-owned orders",
      "expect": "cleanup intents first if needed, then protective SL/TP, then a trusted account-state read before DCA"
    },
    {
      "name": "same_side_position_add_classifies_slots_once",
      "given": "same scope remains open but hydrated quantity or average entry changed",
      "expect": "only changed app-owned slots are amended or replaced according to the slot classifier, and the follow-up pass settles to intentCount=0"
    },
    {
      "name": "dca_2027_blocks_dca_only",
      "given": "DCA placement returns -2027 max position or leverage limit while TP/SL are active or still needed",
      "expect": "DCA slot is blocked or cooled down, protective TP/SL management remains active, and the service does not enter product-wide operator pause"
    },
    {
      "name": "full_close_clears_slot_state_after_cleanup_settled",
      "given": "position is fully closed, cleanup has removed app-owned DCA/TP/SL, and REST hydration shows no matching position or active app-owned orders",
      "expect": "in-memory slot state is cleared and the next same-symbol same-side managed position starts fresh from current account state"
    },
    {
      "name": "log_position_counters_are_unambiguous",
      "given": "Binance returns raw zero-position rows and one non-zero managed position",
      "expect": "logs use rawPositionRows separately from openManagedPositions"
    },
    {
      "name": "position_open_reacts_without_timer",
      "given": "ORDER_TRADE_UPDATE or TRADE_LITE arrives while the symbol-side workflow is idle after flat startup",
      "expect": "event schedules immediate symbol-side reconciliation with scheduledDelayMs=0, uses stream-fed accountstate while trusted, and planner emits SL, TP, DCA without waiting for a periodic timer"
    },
    {
      "name": "usdm_algo_close_position_hydration_defaults",
      "given": "app-owned close-position STOP_MARKET SL hydrates with quantity, price, closePosition, or reduceOnly defaults",
      "expect": "normalizer treats those defaults as equivalent after identity and trigger fields match; intentCount=0 and doNotCancel=true"
    },
    {
      "name": "custom_oid_guard_preflights_before_submit",
      "given": "action family contains an intent with duplicate or in-flight custom ID",
      "expect": "custom ID guard fails before any exchange call"
    },
    {
      "name": "binance_formatted_event_missing_required_path_enters_recovery",
      "given": "formatted private event should clear a pending confirmation but lacks the verified client ID path",
      "expect": "pending confirmation remains uncleared, unresolved-scope mutation is blocked, and scoped recovery is scheduled"
    },
    {
      "name": "private_stream_exception_fails_startup",
      "given": "required USD-M private stream emits SDK exception during startup",
      "expect": "product readiness is recoveryRequired, service_ready is not logged, and live startup fails"
    },
    {
      "name": "deferred_replan_reentrant_calls_are_grouped",
      "given": "multiple user-data events arrive while a same-side-add replacement workflow is active",
      "expect": "one replacement action, one follow-up convergence pass, bounded defer reasons, and no reentrant log storm"
    }
  ],
  "operatorConformanceScript": [
    "Open hedge LONG manually; expect app-owned LONG DCA, TP, and SL.",
    "Cancel all app-owned LONG orders manually while LONG remains open; expect reconciliation to recreate missing LONG DCA, TP, and SL.",
    "Close LONG manually; expect stale LONG app-owned orders to be cleaned without touching unowned orders.",
    "Open hedge SHORT manually; expect app-owned SHORT DCA, TP, and SL.",
    "Open hedge LONG while SHORT remains open; expect both side-specific order sets to coexist.",
    "Increase the SHORT manually; expect only SHORT-side app-owned DCA/TP/SL with changed desired quantity, price, or trigger fields to be cancelled and replaced.",
    "Wait for the next hydration; expect planner intentCount=0 with both side-specific order sets current.",
    "Replay saved formatted ORDER_TRADE_UPDATE, ALGO_UPDATE, TRADE_LITE, and ACCOUNT_UPDATE samples through the adapter; expect the verified field-path matrix to classify each without unresolved-scope mutation.",
    "Run doctor/status with EXECUTION_MODE=LIVE in .env; expect forced safe mode and no exchange-facing order action."
  ],
  "eventBurstPolicy": {
    "immediateEvents": [
      "ORDER_TRADE_UPDATE",
      "ALGO_UPDATE",
      "TRADE_LITE",
      "fills",
      "cancels",
      "rejects",
      "startup",
      "reconnect",
      "unknown submission state",
      "conflicting state"
    ],
    "accountUpdatePositionSubjects": {
      "waitForRelatedEventsMs": {
        "default": 50,
        "max": 250
      },
      "groupBy": "symbol-side"
    },
    "rationale": "Use these as working defaults, not universal proof. Ingest all user-data immediately, trigger strategy only for pending-confirmation clears or position-subject ACCOUNT_UPDATE groups, and avoid spending REST weight for every ordinary event."
  },
  "sourceReferenceNotes": {
    "localVerification": "Verify these lookup targets against installed node_modules before coding.",
    "sdkLookupTargets": [
      "FuturesNewAlgoOrderParams",
      "FuturesNewAlgoOrderParams.positionSide",
      "FuturesNewAlgoOrderParams.closePosition",
      "FuturesNewAlgoOrderParams.reduceOnly",
      "USDMClient.submitNewAlgoOrder(params: FuturesNewAlgoOrderParams)",
      "WsMessageFuturesUserDataTradeUpdateEventFormatted.order.clientOrderId",
      "WsMessageFuturesUserDataAlgoUpdateFormatted.algoOrder.clientAlgoId",
      "WsMessageFuturesUserDataTradeLiteEventFormatted.clientOrderId",
      "WsMessageFuturesUserDataAccountUpdateFormatted.updateData.updatedPositions"
    ],
    "officialDocsRuntimeRules": [
      "USD-M New Algo Order docs: positionSide must be LONG or SHORT in Hedge Mode.",
      "USD-M New Algo Order docs: reduceOnly cannot be sent in Hedge Mode and cannot be sent with closePosition=true."
    ]
  },
  "expectedLogTimeline": [
    "source_verification_complete with package version and method/type list",
    "formatted_private_event_matrix_verified with ORDER_TRADE_UPDATE, ALGO_UPDATE, TRADE_LITE, and ACCOUNT_UPDATE paths",
    "startup_reconciliation_started",
    "product_snapshot_replaced with compact counts",
    "position_classified with exchangePositionSide and managedStrategySide",
    "private_ws_event_received, accountstate_event_applied, and affected_scope_recorded for private updates",
    "stale_app_owned_cleanup_planned before new placement when needed",
    "planner_finished with intentCount and blockedCount",
    "action_family_selected with cleanup, protective, dca, noop, blocked, or recovery",
    "submission_action_started or protective_dispatch_started under workflow owner",
    "submission_accepted_pending_confirmation with role, actionFamily, sanitized request diff/context, and inFlightClientIds count",
    "replan_deferred_workflow_active level=info for expected user_data_* confirmations",
    "processing_deferred_replans with bufferedEventCount",
    "private_ws_confirmation_applied after replay",
    "planner_finished intentCount=0",
    "same_side_position_add_detected with previous and hydrated quantity/entry",
    "managed_order_mismatch_planned with role, client ID, desired quantity/price/trigger, and active quantity/price/trigger",
    "planner_finished intentCount=0 after private confirmation or scoped recovery hydration",
    "failure pattern: repeated planner_finished intentCount>0 with only client ID or metadata changing and no position-state change",
    "deferred_replan_already_replayed skipped=true when buffer is empty",
    "shutdown_summary with counts, readiness, bufferedEventCount, compact positions, compact active app-owned orders"
  ],
  "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."
  },
  "goldenLogTraces": {
    "manualOpen": [
      {
        "event": "private_ws_event_received",
        "eventType": "ORDER_TRADE_UPDATE",
        "symbolSide": "BTCUSDT:LONG"
      },
      {
        "event": "accountstate_event_applied",
        "positions": 1,
        "activeOrders": 0
      },
      {
        "event": "affected_scope_recorded",
        "symbolSide": "BTCUSDT:LONG"
      },
      {
        "event": "action_family_selected",
        "actionFamily": "protective",
        "intentCount": 2
      },
      {
        "event": "protective_dispatch_started",
        "actionFamily": "protective",
        "intentCount": 2,
        "dispatch": "concurrent_separate_orders"
      },
      {
        "event": "submission_accepted_pending_confirmation",
        "role": "SL",
        "kind": "algo_STOP_MARKET",
        "action": "place"
      },
      {
        "event": "submission_accepted_pending_confirmation",
        "role": "TP",
        "kind": "regular_LIMIT",
        "action": "place"
      },
      {
        "event": "private_ws_confirmation_applied",
        "regularOpenOrders": 1,
        "openAlgoOrders": 1
      },
      {
        "event": "action_family_selected",
        "actionFamily": "dca",
        "intentCount": 1
      },
      {
        "event": "submission_accepted_pending_confirmation",
        "role": "DCA",
        "kind": "regular_LIMIT",
        "action": "place"
      },
      {
        "event": "private_ws_confirmation_applied",
        "regularOpenOrders": 2,
        "openAlgoOrders": 1
      },
      {
        "event": "planner_finished",
        "positions": 1,
        "activeOrders": 3,
        "intentCount": 0
      }
    ],
    "sameSideAdd": [
      {
        "event": "planner_finished",
        "positions": 1,
        "activeOrders": 3,
        "classifier": "keep|amend|cancel_place|cancel|place"
      },
      {
        "event": "slot_classified",
        "role": "SL",
        "action": "amend_or_cancel_place",
        "cancelPlaceOnlyWhen": "current Binance package/docs prove the conditional exit slot cannot be amended or its identity changed"
      },
      {
        "event": "slot_classified",
        "role": "TP",
        "action": "amend_or_cancel_place",
        "cancelPlaceOnlyWhen": "current Binance package/docs prove the regular TP slot cannot be amended or its identity changed"
      },
      {
        "event": "slot_classified",
        "role": "DCA",
        "action": "amend_or_cancel_place",
        "cancelPlaceOnlyWhen": "current Binance package/docs prove the regular order slot cannot be amended or its identity changed"
      },
      {
        "event": "trusted_accountstate_read",
        "after": "protective_action_family",
        "reason": "same_side_add"
      },
      {
        "event": "submission_action_started",
        "actionFamily": "dca",
        "requiresPositionStillOpen": true
      },
      {
        "event": "planner_finished",
        "positions": 1,
        "activeOrders": 3,
        "intentCount": 0
      }
    ],
    "hedgeCoexistence": [
      {
        "event": "action_family_selected",
        "actionFamily": "protective",
        "positions": 1,
        "activeOrders": 0,
        "intentCount": 2,
        "side": "LONG"
      },
      {
        "event": "action_family_selected",
        "actionFamily": "protective",
        "positions": 2,
        "activeOrders": 3,
        "intentCount": 2,
        "side": "SHORT"
      },
      {
        "event": "planner_finished",
        "positions": 2,
        "activeOrders": 6,
        "intentCount": 0
      }
    ]
  },
  "knownLiveBugPatterns": [
    "Manual fill reacts only on timer: private event handler buffered events but did not schedule reconciliation.",
    "USD-M Algo SL churn: close-position hydration defaults were compared as meaningful fields.",
    "Fixed TP implemented as Algo conditional: ordinary fixed TP should have used regular LIMIT semantics and missed eligible fills while waiting for trigger behavior.",
    "Lifecycle or replacement generation recovered from client IDs: restart churn and false replacements followed.",
    "Client ID drift listed as the only replacement difference: metadata drove order churn.",
    "DCA -2027 pauses protective management: exposure-limit rejection should block DCA only.",
    "Protective submit before context registration: custom ID guard did not run before the exchange call.",
    "-2011 Unknown order loop: cancel target absent from hydration was not marked terminal or stale.",
    "Formatted private event path mismatch: ORDER_TRADE_UPDATE, ALGO_UPDATE, TRADE_LITE, or ACCOUNT_UPDATE was parsed from the wrong field path, causing missed confirmations or wrong-side routing.",
    "TRADE_LITE unresolved side mutation: fill evidence without positionSide mutated a slot before registry context or ACCOUNT_UPDATE resolved the scope.",
    "-2011 after private terminal proof logged as an alarming error instead of a benign stale-target race.",
    "In-flight client ID stuck: submit threw before cleanup cleared in-flight state.",
    "Startup logs service_ready after SDK exception: subscribe helper completion was treated as readiness.",
    "Deferred replan log storm: reentrant pass scheduled follow-up even though it did not own the active workflow."
  ]
}
