Files
stonks-oracle/.kiro/specs/operator-approval-workflow/bugfix.md
T
Celes Renata b149f70507 fix: operator approval workflow — add approval toggle, lockout CRUD, and PBT tests
- Add GET/PUT /api/admin/trading/approval-config endpoints
- Add POST/DELETE /api/admin/trading/lockouts endpoints
- Add useApprovalConfig, useUpdateApprovalConfig, useCreateLockout, useDeleteLockout hooks
- Add Paper Order Approval toggle card with confirmation dialog
- Add lockout creation form and delete button to Active Lockouts card
- Add MSW handlers for all new endpoints
- Add property-based tests for bug condition exploration and preservation
2026-04-17 06:14:46 +00:00

4.9 KiB

Bugfix Requirements Document

Introduction

The Trading Controls page at /trading has two dead sections — "Pending Approvals" and "Active Lockouts" — that display data from the API but provide no way to actually trigger the underlying workflows. The operator approval system is fully implemented in the backend (services/risk/approval.py, services/adapters/broker_service.py) with an approval gate in the order processing pipeline, but it is effectively disconnected because:

  1. The requires_approval() function returns False in paper mode (the default) since auto_approve_paper defaults to True, and the risk config stored in the database never overrides this default. There is no UI control to toggle approval requirements for paper mode.
  2. The lockout system has a database table (symbol_lockouts) and a read-only API endpoint (GET /api/admin/trading/lockouts), but there is no API endpoint to create a manual lockout and no UI form to do so.

The result is that the operator can never exercise "human calls the final shot" control — orders bypass approval silently, and lockouts can never be created manually.

Bug Analysis

Current Behavior (Defect)

1.1 WHEN the system is in paper trading mode (the default) THEN the requires_approval() function always returns False because OperatorApproval.auto_approve_paper defaults to True and the risk config JSON in the database does not include operator approval settings, causing all orders to bypass the approval gate in process_order_job()

1.2 WHEN the operator views the Trading Controls page THEN the "Pending Approvals" section always shows "(0) — No pending approvals" because no approval requests are ever created due to defect 1.1

1.3 WHEN the operator wants to manually lock out a ticker from trading THEN there is no API endpoint to create a lockout entry in the symbol_lockouts table, so the "Active Lockouts" section is permanently empty unless lockouts are created by internal system processes

1.4 WHEN the operator views the Active Lockouts section on the Trading Controls page THEN there is no UI control to create a new manual lockout or to remove an existing lockout early

1.5 WHEN the operator wants to enable or disable the approval requirement for paper mode THEN there is no UI control on the Trading Controls page to toggle the auto_approve_paper setting in the risk config

Expected Behavior (Correct)

2.1 WHEN the system is in paper trading mode and the operator has disabled auto_approve_paper via the UI THEN the requires_approval() function SHALL return True, causing orders to be held for operator approval before broker submission

2.2 WHEN requires_approval() returns True for the current trading mode THEN orders processed by process_order_job() SHALL create approval requests visible in the "Pending Approvals" section, and the operator SHALL be able to approve or reject them using the existing approve/reject buttons

2.3 WHEN the operator submits a manual lockout via the Trading Controls page (specifying ticker, reason, and duration) THEN the system SHALL create a new entry in the symbol_lockouts table via a new API endpoint, and the lockout SHALL appear in the "Active Lockouts" section

2.4 WHEN the operator views the Active Lockouts section THEN each lockout entry SHALL have a control to remove (cancel) the lockout early, and there SHALL be a form to create a new manual lockout

2.5 WHEN the operator toggles the approval requirement setting on the Trading Controls page THEN the system SHALL update the auto_approve_paper field in the active risk config's JSON, and the change SHALL take effect for subsequent orders without requiring a service restart

Unchanged Behavior (Regression Prevention)

3.1 WHEN the system is in live trading mode with require_approval_for_live set to True (the default) THEN the system SHALL CONTINUE TO require operator approval for live orders as it does today

3.2 WHEN the system is in disabled trading mode THEN the requires_approval() function SHALL CONTINUE TO return False because orders are blocked upstream by the risk engine

3.3 WHEN the operator approves or rejects a pending approval via the existing approve/reject buttons THEN the system SHALL CONTINUE TO update the approval status in the operator_approvals table via the existing PUT /api/admin/trading/approvals/{id} endpoint

3.4 WHEN a pending approval expires (exceeds approval_timeout_minutes) THEN the system SHALL CONTINUE TO mark it as expired via the existing expire_stale_approvals() function

3.5 WHEN the risk engine evaluates an order and it fails risk checks THEN the order SHALL CONTINUE TO be rejected before reaching the approval gate, preserving the existing risk evaluation pipeline

3.6 WHEN system-generated lockouts are created by internal processes (news-shock, cooldown) THEN those lockouts SHALL CONTINUE TO function as they do today, unaffected by the new manual lockout feature