{
  "format": "siebly-agent-recipe/v1",
  "id": "exchange-state-management",
  "title": "Exchange State Management",
  "lastReviewed": "2026-05-12",
  "purpose": "Canonical build path for exchange order, account, and position state-management systems. Use the machine manifest when an executable prompt input is needed.",
  "humanStart": "https://siebly.io/ai/exchange-state",
  "promptStart": "https://siebly.io/.well-known/agent-manifests/exchange-state-management/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."
  },
  "onePromptPath": [
    "Read primarySpec first",
    "Implement accountstate as the trusted WS cache",
    "Trigger debounced reconciliation from accountstate updates",
    "Gate exchange mutations by slot confirmation",
    "Use REST hydration only for startup, reconnect, recovery, or explicit sync-required states",
    "After implementation, generate/run applicable [behavior-contract fixtures](https://siebly.io/reference/glossary#behavior-contract-fixture) before DEMO, TESTNET, or LIVE"
  ],
  "antiTrace": {
    "normalPrivateWsBurstMustNot": [
      "private event -> REST hydrate",
      "REST acceptance -> trusted active order downgrade",
      "confirmed context -> recovery loop",
      "pending confirmation -> duplicate place",
      "execution fill -> open order confirmation"
    ]
  },
  "coreArtifacts": {
    "manifest": "https://siebly.io/.well-known/agent-manifests/exchange-state-management/latest.json",
    "runtimeKit": "https://siebly.io/.well-known/runtime-kits/exchange-state-management/v1/index.json",
    "runtimeTypes": "https://siebly.io/.well-known/runtime-kits/exchange-state-management/v1/types.ts",
    "integrationKit": "https://siebly.io/.well-known/integration-kits/exchange-state-management/latest.json",
    "conformancePack": "https://siebly.io/.well-known/conformance/exchange-state-management/latest.json",
    "schema": "https://siebly.io/.well-known/conformance/exchange-state-management/v1/schema.json",
    "fixtures": "https://siebly.io/.well-known/conformance/exchange-state-management/v1/fixtures.json",
    "runner": "https://siebly.io/.well-known/conformance/exchange-state-management/v1/runner.ts"
  },
  "specSteps": [
    "Save this exact prompt or spec in docs/AI_PROMPT.md (or docs/SPEC.md when that is the project standard), plus the prompt manifest, workflow state machine, private-event routing table, confirmation lifecycle, durable-context lifecycle, plan, and environment example before exchange calls.",
    "Verify installed SDK/API clients, request builders, custom ID fields, private topics, filters, error shapes, reconnect hooks, and shutdown methods from installed declarations/source before coding exchange adapters.",
    "Create the exchange-state runtime modules before exchange-specific adapters. Use the runtime kit when reusable scaffolding or typed module contracts are needed.",
    "After implementation, generate or run local tests from the applicable [behavior-contract fixtures](https://siebly.io/reference/glossary#behavior-contract-fixture) in the exchange-state and selected exchange [conformance packs](https://siebly.io/reference/glossary#conformance-pack) before enabling write-capable execution modes.",
    "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.",
    "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.",
    "Plan protective SL/TP before exposure-increasing DCA for a fresh managed position. DCA runs only after protection is trusted or scoped recovery proves the account state."
  ],
  "minimalSystem": [
    "Use [Account State](https://siebly.io/reference/glossary#accountstate) or the project-local account cache as the only planning state.",
    "After readiness, private events update [Account State](https://siebly.io/reference/glossary#accountstate) as the normal state path.",
    "Use REST state fetches only at trust boundaries: startup, restart, reconnect or gap, missing prerequisites, unknown outcome, timeout, conflict, or explicit recovery.",
    "Order and fill updates trigger reconciliation, but dependent replacement planning waits for matching position or account-state evidence or [scoped recovery](https://siebly.io/reference/glossary#scoped-recovery).",
    "When the exchange does not provide position rows, derive local [position](https://siebly.io/reference/glossary#position) state from fills, fees, and balance/account events before managed exits or exposure changes.",
    "DCA is a configured exposure-increasing order unless another execution style is explicitly selected. TP and SL are protective managed slots."
  ],
  "requiredProjectFiles": [
    "docs/AI_PROMPT.md (or docs/SPEC.md when that is the project standard)",
    "docs/AI_PROMPT_MANIFEST.json",
    "docs/PLAN.md",
    "docs/WORKFLOW_STATE_MACHINE.md",
    "docs/PRIVATE_EVENT_ROUTING_TABLE.md",
    "docs/CONFIRMATION_LIFECYCLE.md",
    "docs/DURABLE_CONTEXT_LIFECYCLE.md",
    ".env.example"
  ],
  "runtimeModulesToCreate": [
    "config loader",
    "exchange adapter",
    "accountstate adapter",
    "order context store",
    "confirmation tracker",
    "affected-scope queue",
    "event-burst scheduler",
    "single workflow owner",
    "planner",
    "submitter",
    "recovery hydrator",
    "structured logger",
    "safe commands"
  ],
  "runtimeLoop": [
    "Startup hydration loads filters, positions or inputs for local position tracking, open orders, fills or executions, wallet or margin state, account mode, risk/readiness state, and stored contexts.",
    "Private stream readiness is established and buffered private events replay into [Account State](https://siebly.io/reference/glossary#accountstate).",
    "Service readiness opens only after hydration, replay, and configuration gates pass.",
    "A private event updates [Account State](https://siebly.io/reference/glossary#accountstate) immediately.",
    "The affected product/symbol/side is recorded as the [affected scope](https://siebly.io/reference/glossary#affected-scope).",
    "A short [event-burst wait](https://siebly.io/reference/glossary#event-burst-wait) gives related order, execution, position, and wallet events time to arrive.",
    "One [workflow owner](https://siebly.io/reference/glossary#workflow-owner) drains one affected scope.",
    "The planner chooses one [action family](https://siebly.io/reference/glossary#action-family).",
    "The submitter sends only the mutations approved by that pass after final gates pass.",
    "Accepted mutations become [pending confirmations](https://siebly.io/reference/glossary#pending-confirmation).",
    "[Private Stream Confirmation](https://siebly.io/reference/glossary#private-stream-confirmation) updates [Account State](https://siebly.io/reference/glossary#accountstate), or [Scoped Recovery](https://siebly.io/reference/glossary#scoped-recovery) resolves unknown outcomes.",
    "Follow-up scopes are requeued only when trusted state changed."
  ],
  "requiredChecks": [
    "startup_hydrated_position_queues_work_before_service_ready",
    "private_event_records_scope_and_schedules_reconcile",
    "private_event_burst_waits_for_related_events",
    "custom_order_id_registry_routes_exchange_echoes",
    "pending_confirmation_does_not_unlock_dependent_action_family",
    "context_write_failure_blocks_submission",
    "private_confirmation_before_rest_accept_is_consumed",
    "side_flip_cleans_old_side_before_new_side_work",
    "pending_place_blocks_duplicate_place",
    "pending_cancel_blocks_duplicate_cancel",
    "decimal_and_default_equivalent_active_order_does_not_replace",
    "terminal_event_during_cancel_or_amend_is_benign_race",
    "reconnect_queues_known_scopes_for_recovery_even_when_quiet",
    "slot_filter_failures_are_blocked_not_silent_or_retried",
    "flat_position_cleans_app_owned_orders"
  ],
  "completeRequiredChecks": [
    "startup_hydrated_position_queues_work_before_service_ready",
    "private_event_records_scope_and_schedules_reconcile",
    "private_event_burst_waits_for_related_events",
    "custom_order_id_registry_routes_exchange_echoes",
    "pending_confirmation_does_not_unlock_dependent_action_family",
    "context_write_failure_blocks_submission",
    "private_confirmation_before_rest_accept_is_consumed",
    "side_flip_cleans_old_side_before_new_side_work",
    "pending_place_blocks_duplicate_place",
    "pending_cancel_blocks_duplicate_cancel",
    "decimal_and_default_equivalent_active_order_does_not_replace",
    "terminal_event_during_cancel_or_amend_is_benign_race",
    "reconnect_queues_known_scopes_for_recovery_even_when_quiet",
    "slot_filter_failures_are_blocked_not_silent_or_retried",
    "flat_position_cleans_app_owned_orders",
    "rest_acceptance_does_not_downgrade_trusted_private_order",
    "terminal_order_status_is_not_open_order_confirmation",
    "execution_fill_is_not_open_order_confirmation",
    "default_dca_active_order_does_not_advance_next_step",
    "startup_adopts_active_contexts_and_prunes_absent_contexts",
    "ambiguous_event_routes_bounded_fallback_then_exact_scope",
    "pending_confirmation_timeout_enters_scoped_recovery",
    "recovery_hydration_blocks_normal_actions_until_trust_restored",
    "blank_symbols_auto_detects_open_positions",
    "absent_symbols_auto_detects_open_positions",
    "blank_symbols_no_positions_noops_without_mutation",
    "symbol_allowlist_manages_matching_detected_positions_only",
    "sample_symbol_not_used_as_runtime_default",
    "configured_symbol_allowlist_blocks_out_of_scope_events",
    "order_confirmation_does_not_imply_position_trust",
    "native_position_dca_fill_waits_for_position_update",
    "native_position_tp_sl_fill_waits_for_position_update",
    "spot_local_position_state_substitutes_for_native_position_rows",
    "long_dca_equal_sl_rejected",
    "short_dca_equal_sl_rejected",
    "dry_run_status_doctor_cannot_submit_live_orders"
  ],
  "notConfirmations": [
    {
      "evidence": "REST place/amend/cancel acceptance",
      "route": "record or match [Pending Confirmation](https://siebly.io/reference/glossary#pending-confirmation)",
      "reason": "Transport or request success does not prove active open-order state."
    },
    {
      "evidence": "Terminal order row",
      "route": "clear or terminalize the matching latch",
      "reason": "Cancelled, rejected, filled, deactivated, triggered, or equivalent rows are not active slot evidence."
    },
    {
      "evidence": "Execution or fill row",
      "route": "update fills and record the affected scope",
      "reason": "Fill evidence can change position/order state but does not confirm active open-order existence or [Position Trust](https://siebly.io/reference/glossary#position-trust)."
    },
    {
      "evidence": "Private order update",
      "route": "update [Order Trust](https://siebly.io/reference/glossary#order-trust), match pending confirmations, and record the affected scope",
      "reason": "[Order Trust](https://siebly.io/reference/glossary#order-trust) is not [Position Trust](https://siebly.io/reference/glossary#position-trust). When the exchange provides position rows, replacement planning waits for a matching position or account-state update or [Scoped Recovery](https://siebly.io/reference/glossary#scoped-recovery)."
    },
    {
      "evidence": "Private stream open or subscription event",
      "route": "update transport readiness only",
      "reason": "Account State readiness still needs hydration, replay, and private account-state evidence."
    },
    {
      "evidence": "Active DCA order for the current step",
      "route": "hold dependent DCA work",
      "reason": "An active DCA order is not permission to place the next DCA step."
    }
  ],
  "subjectTrust": {
    "subjects": [
      "order trust",
      "position trust",
      "filter trust",
      "context trust",
      "readiness trust"
    ],
    "rules": [
      "Split trust by subject: order trust, position trust, filter trust, context trust, and readiness trust.",
      "A TP/SL/DCA order update proves only order trust; it does not prove position trust, position size, entry/cost basis, exposure, or replacement eligibility.",
      "For products with exchange-provided position rows, order/fill events are triggers; replacement planning waits for matching position trust from private position or account updates or scoped recovery.",
      "For products without exchange-provided position rows, derive local position state from fills/executions, fees, account events, balance updates, and documented matching rules before managed exits, exposure changes, or re-hedging."
    ]
  },
  "symbolScope": [
    "If configuredSymbols is blank, absent, or empty, auto-detect eligible open positions.",
    "When symbols are configured, treat them as an allowlist: manage matching detected positions only and ignore or log out-of-scope private events without mutation.",
    "Sample symbols from docs, tests, prompts, or quickstarts are examples only; never use them as runtime defaults."
  ],
  "riskGeometry": [
    "For broad TP/SL/DCA position managers, use percentage-based strategy inputs by default: derive TP, DCA, and SL prices plus DCA size from trusted entry and position size before order planning.",
    "Absolute TP/DCA/SL prices or DCA quantities are advanced per-symbol operator overrides, not the primary config model. If allowed, they must be explicit, scoped, compatible with percentage defaults, and validated through the same filters and risk geometry.",
    "Startup validation rejects missing, invalid, contradictory, or non-finite strategy inputs before private clients, WebSocket subscriptions, hydration, or exchange mutation.",
    "Validate risk geometry before exchange mutation: for long positions, TP is above entry, DCA is below entry, and SL is below DCA; for short positions, TP is below entry, DCA is above entry, and SL is above DCA.",
    "Reject missing or invalid TP/DCA/SL strategy outputs before order placement. After derivation or override, quantize prices and quantities with hydrated exchange filters before final validation.",
    "After quantization, revalidate risk geometry, min/max, and notional rules; reject only if the quantized TP/DCA/SL values are equal, crossed, or otherwise violate geometry or filters before [EXECUTION_MODE](https://siebly.io/reference/glossary#execution-mode)=DRY_RUN_PRIVATE, DEMO, TESTNET, or LIVE order placement.",
    "Risk geometry validation uses the trusted entry price or explicit operator override, hydrated tick/lot filters, and the managed side before any place/amend/cancel request."
  ],
  "identityChainReview": {
    "cleanPassesRequired": 3,
    "chain": [
      "config scope",
      "product/environment/account",
      "symbol",
      "position mode",
      "managed side",
      "exchange position identity",
      "accountstate position state (native or locally derived)",
      "planner scope",
      "slot scope",
      "custom order ID",
      "durable context",
      "exchange request",
      "REST acceptance",
      "private order/execution/position event",
      "trusted active order",
      "subject trust state",
      "confirmation tracker",
      "recovery scope",
      "cleanup/protective/DCA replanning"
    ],
    "requiredRule": "Do not mark the implementation complete until three consecutive full identity-chain review passes produce no code, tests, fixtures, or documentation changes.",
    "passMustTrace": "Trace mismatched, stale, missing, contradictory, duplicated, late, recovered, and flat identities across every runtime boundary."
  },
  "liveRunFailureFixtures": [
    {
      "name": "context_write_failure_blocks_submission",
      "purpose": "A failed durable order-context write must block exchange submission.",
      "expected": "The planner records the context write failure, submits no order, creates no pending confirmation, and leaves the scope blocked or recovery-ready."
    },
    {
      "name": "private_confirmation_before_rest_accept_is_consumed",
      "purpose": "A private confirmation can arrive before the REST submit promise resolves.",
      "expected": "The early private confirmation is retained, matched to the later accepted submit response, and does not leave stale pending state or duplicate submission."
    },
    {
      "name": "side_flip_cleans_old_side_before_new_side_work",
      "purpose": "A one-way side flip cleans old-side app-owned orders before new-side protection or DCA.",
      "expected": "Cleanup for the old managed side settles first; new-side protective and DCA work stays blocked until the cleanup confirmation is trusted."
    },
    {
      "name": "pending_place_blocks_duplicate_place",
      "purpose": "A pending place confirmation blocks another place for the same slot.",
      "expected": "The planner emits no duplicate place intent while the matching place confirmation is still pending."
    },
    {
      "name": "pending_cancel_blocks_duplicate_cancel",
      "purpose": "A pending cancel confirmation blocks another cancel for the same target.",
      "expected": "The planner emits no duplicate cancel intent while the matching cancel confirmation is still pending."
    },
    {
      "name": "decimal_and_default_equivalent_active_order_does_not_replace",
      "purpose": "Equivalent active orders do not churn because of display precision or hydrated defaults.",
      "expected": "Desired-vs-active comparison normalizes decimals and non-actionable exchange defaults by order kind, then suppresses cancel/recreate when actionable slot fields match."
    }
  ],
  "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."
  ],
  "exchangeOverlays": [
    "https://siebly.io/.well-known/agent-manifests/binance-position-manager/latest.json",
    "https://siebly.io/.well-known/agent-manifests/bybit-position-manager/latest.json"
  ],
  "promptFrameworkCompletionWorkflow": {
    "instruction": "Recursive completion workflow:\n1. Before implementation, save this exact prompt in docs/AI_PROMPT.md (or docs/SPEC.md when that is the project standard) and write docs/PLAN.md with phases, invariants, tests or fixtures, docs to update, and acceptance gates.\n2. Review docs/PLAN.md for missing workflows, unsafe assumptions, product/exchange-specific leakage, unclear state ownership, confirmation or recovery gaps, missing tests, and incomplete docs. Update docs/PLAN.md and repeat until one full review pass finds no actionable changes.\n3. Implement one plan phase at a time. After each phase, review changed code, tests, fixtures, docs, generated artifacts, and runtime workflows against docs/PLAN.md and this prompt. Fix gaps and repeat until that phase has no actionable changes before starting the next phase.\n4. After all phases, run a full-depth project review across every workflow, lifecycle, state transition, error path, and artifact. This is not a shallow summary pass. Fix every actionable gap and repeat until a full pass finds no further changes, then record the final review outcome in docs/PLAN.md.",
    "acceptanceRequirement": "docs/PLAN.md records the initial plan, plan-review iterations, phase review outcomes, final full-project review, validation commands, and any documented non-claims. No plan phase or project completion is accepted until the recursive review loop finds no actionable gaps, flaws, or incomplete workflows left to correct."
  }
}
