{
  "format": "siebly-integration-kit/v1",
  "id": "position-manager-core",
  "title": "Exchange State Management Integration Kit",
  "lastReviewed": "2026-05-03",
  "purpose": "Exchange-neutral runtime contract for order/position state-management systems. Exchange-specific kits add SDK methods, request fields, topics, and error codes.",
  "criticalPathGuide": "https://siebly.io/ai/position-manager/critical-path",
  "agentImplementationManifest": "https://siebly.io/.well-known/agent-manifests/position-manager-core/latest.json",
  "runtimeKit": "https://siebly.io/.well-known/runtime-kits/position-manager-core/v1/index.json",
  "conformancePack": "https://siebly.io/.well-known/conformance/position-manager-core/latest.json",
  "architecture": {
    "id": "order_position_state_machine",
    "lane": "ws_symbol_side_phase_gated",
    "eventOrder": [
      "ingest_private_event",
      "apply_accountstate_update",
      "route_row_decision",
      "mark_dirty_scope",
      "schedule_quiet_window_reconcile",
      "run_one_workflow_owner",
      "select_one_phase",
      "record_pending_confirmation",
      "wait_for_trusted_state_or_recovery"
    ],
    "phaseOrder": [
      "recovery",
      "cleanup",
      "protective",
      "dca",
      "noop",
      "blocked"
    ]
  },
  "buildPath": [
    "Read the critical workflow.",
    "Use the task manifest for generation.",
    "Implement the runtime kit module contracts.",
    "Generate tests from the required conformance pack.",
    "Implement the smallest manager that passes the required behavior checks before adding features.",
    "Use broad SDK docs only to verify method names and request shapes."
  ],
  "runtimeModules": [
    {
      "name": "OrderContextStore",
      "owns": "customOrderId -> order context",
      "contract": "Register context before submit, persist when configured, prune against trusted active orders, and never recover slot meaning by parsing custom IDs."
    },
    {
      "name": "AccountState",
      "owns": "trusted positions, active orders, fills, balances, filters, readiness, and sync/recovery flags",
      "contract": "Apply startup/recovery REST snapshots and private events into one account view. REST submit acceptance is coordination evidence only."
    },
    {
      "name": "PrivateEventRouter",
      "owns": "event classification, accountstate ingestion, dirty-scope marking, and pending-confirmation matches",
      "contract": "Ingest private rows immediately, route known custom IDs through OrderContextStore, use bounded fallback scopes for ambiguous rows, and keep wallet-only events out of broad DCA/TP/SL planning unless configured."
    },
    {
      "name": "DirtyScopeQueue",
      "owns": "deduped product/symbol/side work items",
      "contract": "Canonicalize scope keys, dedupe repeats, preserve bounded follow-up reasons, and drain through one workflow owner."
    },
    {
      "name": "DebouncedReconciler",
      "owns": "quiet-window scheduling for private event bursts",
      "contract": "Apply events to AccountState immediately, then run one reconcile after the quiet window with a bounded max delay."
    },
    {
      "name": "ConfirmationTracker",
      "owns": "pending place/amend/cancel confirmations and in-flight custom IDs",
      "contract": "REST acceptance creates pending coordination state. Trusted private state or scoped recovery clears it. Timeout enters scoped recovery."
    },
    {
      "name": "RecoveryHydrator",
      "owns": "scoped REST hydration for untrusted subjects",
      "contract": "When recoveryRequired or sync-required state is set, hydrate positions, open orders, fills/executions, balances/readiness, replay buffered events, clear recovery on success, and requeue affected scopes."
    },
    {
      "name": "WorkflowOwner",
      "owns": "single active reconciliation/planning/submission pass",
      "contract": "Drain one dirty scope at a time. If already active, record follow-up work and let the owner schedule one deferred pass."
    },
    {
      "name": "Planner",
      "owns": "desired managed slots and one selected phase",
      "contract": "Plan from trusted AccountState. Phase order is recovery, cleanup, protective, dca, noop, blocked. Submit at most one phase per pass."
    },
    {
      "name": "SubmissionExecutor",
      "owns": "preflight, context registration, exchange call dispatch, and provisional mutation records",
      "contract": "Pre-register contexts, preflight filters and duplicate IDs, dispatch fresh SL/TP concurrently by default, and never unlock dependent phases from REST acceptance alone."
    },
    {
      "name": "ExchangeErrorClassifier",
      "owns": "deterministic block, benign race, retry/backoff, and scoped recovery decisions",
      "contract": "Classify by action, role, exchange code, current trusted state, and proof. Unknown mutation status enters scoped recovery."
    },
    {
      "name": "StructuredLogger",
      "owns": "redacted lifecycle, planner, submission, recovery, and shutdown logs",
      "contract": "Emit semantic counters and reasons without raw private payloads, secrets, signatures, listen keys, or raw order intents."
    }
  ],
  "behaviorContract": {
    "architecture": "ws_symbol_side_phase_gated",
    "reusableArchitecture": "order_position_state_machine",
    "reusablePrimitives": [
      "custom-order-id-registry",
      "trusted-accountstate-boundary",
      "ws-first-order-state",
      "recovery-hydrate-replan",
      "dirty-scope-event-routing",
      "protective-sl-tp-dispatch",
      "mutation-confirmation-gating",
      "stale-mutation-noop-classification",
      "slot-convergence",
      "latch-lifecycle",
      "conformance-fixture-schema"
    ],
    "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.",
    "slotIdentity": "Use deterministic internal SlotKey values for strategy identity. Exchange-visible custom order IDs are opaque 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": "Generate an opaque custom ID, store context keyed by that ID before submission, send the order with that ID, and look up context when private events return the ID. Apply exchange-specific prefix/length/character rules only where the SDK or exchange requires them.",
    "startupRecovery": "On startup, reconnect, or recovery, hydrate current state, manage orders proven app-owned by the runtime/persisted store, optionally clean unknown scoped orders only when explicit config enables it, wait for private stream confirmation or scoped recovery hydration, then rebuild expected slots from current positions.",
    "healthyStream": "After startup, healthy private account-event bursts are the normal convergence path: ingest private events into account state, emit semantic WS/accountstate logs, mark affected symbol-side scopes dirty, debounce/coalesce by symbol-side, plan from trusted account state, dispatch the selected phase, wait for private stream confirmation or scoped recovery hydration, then replan from stream-fed state.",
    "restBoundary": "REST hydration is for startup, reconnect, exception/gap, sync-required or not-ready state, rejected/unknown/conflicting submissions, and explicit recovery. It is not the ordinary per-event confirmation source.",
    "phaseGate": "Use the fixed ws_symbol_side_phase_gated phase order: recovery > cleanup > protective > dca > noop > blocked. Recovery/sync-required state hydrates first and blocks normal cleanup, protective, and DCA planning until trusted state is restored. A workflow pass may submit cleanup, protective, or DCA actions, but never more than one of those phases.",
    "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 and duplicate-submit protection. They may update local in-flight state for observability, but they do not make dependent phases eligible until the private stream or scoped recovery hydration confirms the account-state outcome.",
    "submissionTimeout": "Use a configurable bounded confirmation timeout for unknown REST/WS outcomes; 5 seconds is a reasonable generated simple-lane default. Unknown outcomes enter scoped recovery rather than duplicate submit or trusted success.",
    "slotConvergence": "Regular fixed-price TP and DCA LIMIT slots converge by slot identity, order side, quantity, and resting 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.",
    "semanticWsLogs": "Emit semantic logs for private stream ingestion and account-state application: private_ws_event_received, accountstate_event_applied, symbol_side_dirty_marked, symbol_side_reconcile_started, phase_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."
  },
  "forbiddenDesigns": [
    "Do not encode symbol, side, role, step, order kind, lifecycle epoch, replacement generation, recovery state, or durable strategy state in exchange-visible client/order IDs for the simple manager.",
    "Do not recover strategy meaning from exchange-visible IDs after restart for the simple 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 when the intended behavior is a resting limit already on the book.",
    "Do not REST-hydrate after every healthy private account event.",
    "Do not REST-hydrate as the normal post-cancel confirmation path while the private stream is healthy.",
    "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.",
    "Do not submit protective exits and exposure-increasing DCA in the same first pass for a newly discovered position.",
    "Do not let accepted submit responses unlock later phases until the private stream or scoped recovery hydration confirms account state."
  ],
  "notConfirmations": [
    {
      "evidence": "REST place/amend/cancel acceptance",
      "route": "record or match 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 resting slot evidence."
    },
    {
      "evidence": "Execution or fill row",
      "route": "update fills and dirty the affected scope",
      "reason": "Fill evidence can change position/order state but does not confirm active open-order existence."
    },
    {
      "evidence": "Private stream open or subscription event",
      "route": "update transport readiness only",
      "reason": "Accountstate readiness still needs hydration, replay, and private account-state evidence."
    },
    {
      "evidence": "Active DCA order for the current step",
      "route": "hold dependent DCA work",
      "reason": "A resting DCA order is not permission to place the next DCA step."
    }
  ],
  "recoveryRule": "When recoveryRequired or sync-required state is set, hydrate/replay/replan before normal cleanup, protective, or DCA phases. Pre-hydration cleanup is an advanced exception, not the generated default.",
  "confirmationLifecycle": [
    "Register order context before submit.",
    "Record in-flight mutation before the exchange call.",
    "Ingest private confirmations even if they arrive before REST settles.",
    "REST acceptance creates or matches pending confirmation only.",
    "Trusted private state or scoped recovery clears pending confirmation.",
    "Timeout or ambiguity enters scoped recovery instead of duplicate submit."
  ],
  "requiredChecks": [
    {
      "name": "startup_hydrated_position_queues_work_before_service_ready",
      "purpose": "REST-hydrated open positions queue work before service readiness.",
      "expected": "Hydration marks affected scopes dirty and a reconciliation pass runs before service_ready."
    },
    {
      "name": "private_event_marks_dirty_and_schedules_reconcile",
      "purpose": "Private event ingestion leads to scoped workflow scheduling.",
      "expected": "The event applies to accountstate, marks the precise or bounded scope dirty, and schedules reconciliation."
    },
    {
      "name": "private_event_burst_debounces_until_quiet_window",
      "purpose": "Accountstate ingestion is immediate while workflow execution waits for the burst to quiet.",
      "expected": "Multiple related events produce one reconcile after quietWindowMs, bounded by maxDelayMs."
    },
    {
      "name": "opaque_custom_id_registry_routes_exchange_echoes",
      "purpose": "Exchange-visible custom IDs are lookup keys into one order-context store.",
      "expected": "Private order echoes map to slot, scope, role, and pending action through the registry without parsing the ID string."
    },
    {
      "name": "pending_confirmation_does_not_unlock_dependent_phase",
      "purpose": "Accepted mutation responses are provisional and cannot unlock dependent phases.",
      "expected": "Dependent phases wait for trusted private stream state or scoped recovery hydration."
    },
    {
      "name": "private_confirmation_before_rest_accept_is_consumed",
      "purpose": "A private confirmation can arrive before the REST promise resolves.",
      "expected": "The early confirmation is retained and consumed when the REST accept path records pending state."
    },
    {
      "name": "terminal_event_during_cancel_or_amend_is_benign_race",
      "purpose": "Terminal private evidence can make later missing-target cancel/amend errors benign.",
      "expected": "The target is terminalized and no duplicate recovery loop starts when proof exists."
    },
    {
      "name": "reconnect_queues_known_scopes_for_recovery_even_when_quiet",
      "purpose": "Reconnect schedules recovery even without a later private event.",
      "expected": "Known active scopes enter scoped hydration and replan from trusted state before new exposure resumes."
    },
    {
      "name": "slot_filter_failures_are_blocked_not_silent_or_retried",
      "purpose": "Exchange filters and local sizing gates produce explicit blocks.",
      "expected": "Min quantity, min notional, zero-size, or missing-filter cases log a block reason and do not spin retries."
    },
    {
      "name": "flat_position_cleans_app_owned_orders",
      "purpose": "A flat position cleans remaining managed orders.",
      "expected": "Only app-owned orders in the affected scope are cancelled or terminalized; unowned orders are untouched."
    }
  ],
  "completeRequiredChecks": [
    "startup_hydrated_position_queues_work_before_service_ready",
    "private_event_marks_dirty_and_schedules_reconcile",
    "private_event_burst_debounces_until_quiet_window",
    "opaque_custom_id_registry_routes_exchange_echoes",
    "pending_confirmation_does_not_unlock_dependent_phase",
    "private_confirmation_before_rest_accept_is_consumed",
    "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_phases_until_trust_restored",
    "configured_symbol_allowlist_blocks_out_of_scope_events",
    "dry_run_status_doctor_cannot_submit_live_orders"
  ],
  "runnerContract": {
    "language": "typescript",
    "fixtureSource": "TypeScript fixture definitions with JSON projections for docs and cross-language use",
    "entrypoint": "https://siebly.io/.well-known/conformance/position-manager/v1/runner.ts",
    "exportedTypes": [
      "PositionManagerFixture",
      "PositionManagerFixtureStep",
      "PositionManagerFixtureExpectation",
      "PositionManagerHarness",
      "PositionManagerFixtureReport",
      "runPositionManagerFixtures"
    ],
    "requiredFixtureFields": [
      "name",
      "intent",
      "scope",
      "initial",
      "steps",
      "expect",
      "forbid"
    ]
  },
  "exchangeOverlays": {
    "binance": "https://siebly.io/.well-known/integration-kits/binance-position-manager/latest.json",
    "bybit": "https://siebly.io/.well-known/integration-kits/bybit-position-manager/latest.json"
  }
}
