{
  "format": "siebly-runtime-kit/v1",
  "id": "position-manager-core-runtime",
  "title": "Exchange State Management Runtime Kit",
  "lastReviewed": "2026-05-03",
  "purpose": "Compact module contract for exchange order/position state-management runtimes.",
  "canonicalArtifacts": {
    "manifest": "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",
    "runtimeTypes": "https://siebly.io/.well-known/runtime-kits/position-manager-core/v1/types.ts",
    "integrationKit": "https://siebly.io/.well-known/integration-kits/position-manager-core/latest.json",
    "conformancePack": "https://siebly.io/.well-known/conformance/position-manager-core/latest.json",
    "fixtures": "https://siebly.io/.well-known/conformance/position-manager/v1/fixtures.json",
    "runner": "https://siebly.io/.well-known/conformance/position-manager/v1/runner.ts"
  },
  "moduleOrder": [
    "OrderContextStore",
    "AccountState",
    "PrivateEventRouter",
    "DirtyScopeQueue",
    "DebouncedReconciler",
    "ConfirmationTracker",
    "RecoveryHydrator",
    "WorkflowOwner",
    "Planner",
    "SubmissionExecutor",
    "ExchangeErrorClassifier",
    "StructuredLogger"
  ],
  "modules": [
    {
      "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."
    }
  ],
  "workflow": {
    "eventFlow": [
      "private_event_received",
      "accountstate_applied",
      "confirmation_match_checked",
      "dirty_scope_marked",
      "quiet_window_scheduled",
      "workflow_owner_drains_scope",
      "planner_selects_one_phase",
      "submission_records_pending_confirmation",
      "private_or_recovery_state_confirms"
    ],
    "phaseOrder": [
      "recovery",
      "cleanup",
      "protective",
      "dca",
      "noop",
      "blocked"
    ],
    "recoveryRule": "recoveryRequired or sync-required state blocks cleanup, protective, and DCA planning until scoped hydration succeeds and the affected scope is requeued.",
    "dependencyRule": "Dependent phases require trusted private state or scoped recovery evidence, not REST acceptance."
  },
  "exchangeAdapterBoundary": {
    "owns": [
      "SDK clients and method names",
      "custom ID field names and prefix rules",
      "request field builders",
      "private topic names and payload field mapping",
      "exchange rejection taxonomy",
      "filter parsing and decimal formatting"
    ],
    "mustNotOwn": [
      "second account-state reducer",
      "custom-ID state encoding",
      "parallel workflow owner",
      "broad REST hydration on every healthy private event"
    ]
  },
  "localFilesToCreate": [
    "src/state/accountState.ts",
    "src/state/orderContextStore.ts",
    "src/stream/privateEventRouter.ts",
    "src/workflow/dirtyScopeQueue.ts",
    "src/workflow/reconciler.ts",
    "src/workflow/confirmationTracker.ts",
    "src/workflow/recoveryHydrator.ts",
    "src/workflow/planner.ts",
    "src/submission/submissionExecutor.ts",
    "src/exchange/errorClassifier.ts",
    "src/logging/logger.ts"
  ],
  "testHooks": [
    "fake clock for debounce and confirmation timeout",
    "fake exchange REST client for hydrate/place/amend/cancel outcomes",
    "private event injector",
    "structured log collector",
    "accountstate snapshot reader",
    "dirty queue inspector"
  ],
  "requiredChecks": [
    "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"
  ]
}
