unrip/IMPLEMENTATION.md
philipp 0902cb2c93 Open implementation turn: Quote lifecycle investigator
Proof: Establish the approved quote lifecycle investigator turn so missed and pending quotes can be followed from durable dashboard evidence.

Assumptions: The selected I012 traceability scope is the approved next slice, while broader quote analytics remain future backlog work.

Still fake: This is a planning commit only; the dashboard investigator, durable lookup endpoint, tests, deployment, and live evidence are not implemented yet.
2026-06-12 19:03:13 +02:00

8.6 KiB

Implementation Turn: Quote lifecycle investigator and missed quote follow-up

Status: open Opened: 2026-06-12

Goal

Improve the dashboard Quote lifecycle view so operators can pin, search, and follow missed or pending quotes from durable evidence even after live rows move on.

Selected Backlog Items

  • [I012] Quotes and execution analytics workbench: live quote tape, quote count and volume windows, size-bucket distributions, oracle-deviation views, per-quote decision and execution trace, and matched-only filters.

This turn intentionally implements only the per-quote lifecycle investigation and missed-quote follow-up part of I012. Remaining analytics-workbench work has been re-added to backlog as follow-on scope.

Constraints

  • Preserve trading behavior: no strategy, pricing, threshold, notional, inventory, arming, signer, pair enablement, quote skip, or relay policy changes.
  • Do not add active pair, edge, notional, latency, response-policy, or retention env vars.
  • Do not introduce a new storage system or retention policy.
  • Preserve existing lifecycle and executor result rows as readable.
  • Use repo workflow for deployment only; no manual kubectl rollout or image patching.
  • Add regression tests for every bug fix or behavior contract introduced here.

Current Shape To Inspect

  • src/operator-dashboard/static/pages/StrategyPage.jsx
    • QuoteLifecycleSection
    • QuoteLifecycleTable
    • LifecycleDetails
    • pause/filter/expanded-row behavior
  • src/operator-dashboard/static/state/dashboardReducer.js
    • quote_lifecycle.updated handling
  • src/core/operator-dashboard.mjs
    • deriveQuoteLifecycleRows
    • buildLiveQuoteLifecycleRows
    • buildStrategySummary
    • lifecycle row normalization/enrichment
  • src/lib/postgres.mjs
    • recent quote, decision, command, execution result, and outcome loaders
  • src/apps/operator-dashboard.mjs
    • bootstrap data loading
    • REST API routes
    • WebSocket update path
  • Existing dashboard/static tests under test/.

Implementation Plan

1. Add a durable lifecycle lookup contract

  • Add a backend loader that can find lifecycle evidence by one identifier:
    • quote_id
    • decision_id
    • command_id
  • Reuse existing durable tables and normalizers:
    • swap_demand_events
    • trade_decisions
    • execute_trade_commands
    • trade_execution_results
    • quote outcomes table
  • Return the same normalized lifecycle row shape produced by deriveQuoteLifecycleRows, enriched for UI in the same way as recent rows.
  • Include lookup metadata:
    • requested identifier
    • matched identifier type
    • found/not found
    • lookup timestamp
    • latest stage timestamp
  • If no row is found, return a structured not-found response instead of a dashboard error.
  • Make missing old fields render as null/Unavailable; do not require new timing fields to exist.

2. Expose a dashboard API endpoint

  • Add an authenticated operator-dashboard route for lifecycle lookup, for example:
    • GET /api/strategy/quote-lifecycle/:identifier
  • The endpoint should:
    • validate a non-empty identifier
    • call the durable lookup loader
    • return { ok, lifecycle_row, lookup }
    • return a 404-style payload for not found without crashing the dashboard
  • Do not expose secrets or raw relay payloads beyond what existing lifecycle rows already show.

3. Improve frontend state and interaction model

  • Replace the current "pause solves investigation" behavior with a selected quote investigator:
    • row action: inspect or pin quote
    • selected row highlight
    • stable investigator panel above the table or directly below controls
    • selected quote remains visible even when filters change or live rows move
  • Keep pause as table-only:
    • paused table keeps row order and row contents stable
    • selected investigator can still refresh from durable lookup
    • resume table applies latest rolling rows without clearing the selected quote
  • Add identifier lookup:
    • search input for quote id, decision id, or command id
    • loading, found, not-found, and error states
    • copyable identifiers remain available
  • Add problem-state filters without changing lifecycle data:
    • all
    • awaiting executor
    • approved/no command
    • blocked before submit
    • submission failed
    • quote not found or finished
    • strategy rejected
    • submitted/awaiting outcome
  • Ensure filters do not hide or clear the selected investigator.

4. Make Awaiting executor explain the next step

  • In the investigator panel, show a concise stage status:
    • quote observed
    • strategy decision
    • command recorded or missing
    • executor result recorded or missing
    • relay/outcome status when present
  • For command_emitted / Awaiting executor rows:
    • show command age using the current clock
    • show the command id and command timestamp
    • show "waiting for executor result" only when no result is found
    • if a later lookup finds an executor result, show the terminal status instead of stale awaiting text
  • For relay failures, make quote_not_found_or_finished visible as a first-class reason.

5. Keep live updates and lookup refresh coherent

  • When quote_lifecycle.updated arrives:
    • update the rolling table as it does today
    • if the selected quote appears in the live payload, refresh the selected panel from that row immediately
    • if the selected quote is absent from the live payload, schedule or expose a durable lookup refresh for the selected identifier
  • Avoid unbounded request loops:
    • debounce lookup refreshes client-side
    • do not add new env vars for refresh timing
    • keep manual refresh available
  • Show whether selected evidence came from:
    • current live rows
    • durable lookup
    • not found
    • lookup error

6. Preserve layout quality

  • Keep the lifecycle table full-width and scan-friendly.
  • Avoid large marketing-style or decorative redesign.
  • Keep row heights stable with existing fixed row slots.
  • Ensure long quote ids and reason text truncate or wrap intentionally.
  • Do not nest cards inside cards; use a panel/detail layout consistent with the existing dashboard.
  • Keep old rows with missing fields readable on desktop and mobile widths.

7. Tests

  • Add or update core tests for lifecycle lookup and row derivation:
    • command-only row classifies as Awaiting executor
    • later executor result for the same quote updates the lifecycle state
    • old rows missing timing fields normalize safely
  • Add backend API tests or static route tests:
    • lookup by quote id
    • lookup by decision id
    • lookup by command id
    • not-found response
  • Add frontend/static tests proving:
    • Quote lifecycle has a selected/pinned investigator
    • pause language is table-specific
    • identifier lookup controls exist
    • problem-state filters include awaiting executor and quote-not-found/finished
    • selected investigation is not represented only by expanded table rows
  • Add a regression test for the described bug:
    • start with a selected Awaiting executor quote
    • update the displayed recent list so that quote is absent
    • prove the selected quote detail remains available or can be refreshed from durable lookup

8. Validation Commands

  • Run targeted tests first, likely:
    • node --test test/operator-dashboard*.test.mjs test/*lifecycle*.test.mjs
    • add narrower filenames as tests are introduced
  • Run full:
    • npm test
  • Build dashboard bundle:
    • npm run operator-dashboard:build

9. Commit, deploy, and evidence

  • Commit implementation with required body:
    • Proof: ...
    • Assumptions: ...
    • Still fake: ...
  • Push only if tests and dashboard build pass.
  • Let repo workflow deploy; do not manually patch deployments.
  • Collect live evidence after deploy:
    • deployments on the new image
    • dashboard still receives live lifecycle updates
    • durable lookup returns at least one recent quote lifecycle row
    • an unresolved or missed quote can be inspected by identifier without relying on it being visible in the rolling table
    • selected quote UI does not clear on live row movement

Assumptions

  • Existing durable quote, decision, command, execution result, and outcome rows are sufficient to reconstruct a single quote lifecycle.
  • The dashboard can add a small authenticated read endpoint without changing service topology.
  • Client-side debounce plus manual refresh is enough to keep pinned quote investigation fresh without adding a new response-policy or retention setting.

Still Fake

  • Venue-native terminal fill truth remains incomplete where outcome rows only infer not-filled or settlement through existing attribution.
  • Fee-aware realized PnL and broader quote analytics workbench views remain out of scope.
  • Historical detail that has already been pruned cannot be reconstructed beyond existing rollups.