From 8805282f5977fd8791206efb9d402e627cd13b05 Mon Sep 17 00:00:00 2001 From: philipp Date: Fri, 12 Jun 2026 19:43:16 +0200 Subject: [PATCH] Archive implementation turn: Quote lifecycle investigator and missed quote follow-up Proof: Preserve the completed implementation turn and record its outcome in the tracked archive. Assumptions: The archived files capture the relevant planning state for the completed turn. Still fake: Archiving does not validate the work by itself; external evidence still governs whether the result is trustworthy. --- ARCHIVE.md | 1 + IMPLEMENTATION.md | 191 +----------------- PROOF.md | 81 +------- ...d-missed-quote-follow-up-implementation.md | 190 +++++++++++++++++ ...igator-and-missed-quote-follow-up-proof.md | 80 ++++++++ 5 files changed, 277 insertions(+), 266 deletions(-) create mode 100644 archive/implementation/20260612T174316Z-quote-lifecycle-investigator-and-missed-quote-follow-up-implementation.md create mode 100644 archive/implementation/20260612T174316Z-quote-lifecycle-investigator-and-missed-quote-follow-up-proof.md diff --git a/ARCHIVE.md b/ARCHIVE.md index 7a5a721..5fb3401 100644 --- a/ARCHIVE.md +++ b/ARCHIVE.md @@ -23,6 +23,7 @@ Legacy note: - 2026-06-06: `maker-response-latency-and-quote-competitiveness` closed with status `passed`. Durable maker timing, relay failure classification, pair-native competitiveness surfaces, dashboard cleanup, and emergency quote-history retention fixes were implemented, validated, and deployed; long-term storage shape is opened as a separate turn. - 2026-06-12: `quote-lifecycle-retention-and-analytics-rollups` closed with status `paused`. Paused after retention, dashboard, semantic, and notification fixes were deployed; the next urgent proof is removing verifier salt refresh from the quote execution hot path. - 2026-06-12: `verifier-salt-hot-path-removal-and-executor-queue-guardrails` closed with status `passed`. Verifier current_salt RPC was removed from the quote-response hot path, cached salt failures now reject before signing or relay, queue delay and salt health are visible and alertable, and live post-deploy evidence showed cache or unavailable salt results with no new-runtime refresh rows. +- 2026-06-12: `quote-lifecycle-investigator-and-missed-quote-follow-up` closed with status `passed`. Durable quote lookup, pinned lifecycle investigator, regression tests, workflow deploy, and live lookup evidence passed on cb87910. ## Research Turns ## Planning Events diff --git a/IMPLEMENTATION.md b/IMPLEMENTATION.md index 2a8b793..c6b72a8 100644 --- a/IMPLEMENTATION.md +++ b/IMPLEMENTATION.md @@ -1,190 +1,5 @@ -# Implementation Turn: Quote lifecycle investigator and missed quote follow-up +# Implementation Turn -Status: open -Opened: 2026-06-12 +Status: idle -## 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. +No approved implementation turn is active yet. diff --git a/PROOF.md b/PROOF.md index b5ddb12..71baf39 100644 --- a/PROOF.md +++ b/PROOF.md @@ -1,80 +1,5 @@ -# Implementation Proof: Quote lifecycle investigator and missed quote follow-up +# Implementation Proof -Status: open -Opened: 2026-06-12 +Status: idle -## Hypothesis -If the operator dashboard turns the quote lifecycle table into a durable quote investigator, an operator can pause or filter the live quote list, select an `Awaiting executor` or otherwise missed quote, and continue following that exact quote through command, executor result, relay failure, outcome, or unresolved state even after the rolling live table moves on. - -## Problem Evidence -- The current Quote lifecycle page is a rolling live table of recent rows. -- Pausing freezes the displayed table snapshot, including stale `Awaiting executor` evidence. -- When live updates resume, the quote can leave the recent window and become hard to find again. -- The existing expandable row explains the lifecycle only while the row remains in the rendered recent set. -- This prevents practical investigation of missed quotes such as commands that later become `quote_not_found_or_finished`, `verifier_salt_unavailable`, stale command rejects, or successful submissions. - -## Scope -- Improve the existing `Quote lifecycle` dashboard view, not a new dashboard product area. -- Add a durable quote lookup path by `quote_id`, `decision_id`, or `command_id` using existing history tables. -- Add a selected or pinned quote investigator that remains visible independently from the rolling table rows. -- Make pause freeze table ordering only; the selected quote investigation must still refresh from durable evidence. -- Add search or lookup controls so a quote can be found again after it leaves the recent table. -- Add filters for investigation states that matter to missed quotes: - - awaiting executor - - approved but command missing - - blocked before submit - - submission failed - - quote not found or finished - - strategy rejected - - submitted or awaiting outcome -- Improve the selected quote detail so `Awaiting executor` clearly shows: - - command id and command timestamp - - elapsed time since command - - whether an executor result is now stored - - relay result or block reason if present - - next expected stage when still unresolved -- Preserve old executor result and lifecycle rows as readable when newer timing or result fields are missing. -- Keep the implementation read-side and dashboard-only unless a small shared lifecycle normalizer change is required. - -## Non-goals -- Do not change strategy selection, pricing, edge thresholds, notional limits, inventory checks, arming, signer identity, or pair enablement. -- Do not skip quotes or alter executor/relay response behavior. -- Do not add active pair, edge, notional, latency, response-policy, or retention environment variables. -- Do not add a new retention policy or new long-term analytics store in this turn. -- Do not build the full remaining analytics workbench: quote volume windows, size-bucket distributions, oracle-deviation views, and matched-only PnL analytics remain backlog work. -- Do not claim submitted quote responses are completed trades unless durable outcome and settlement evidence support that claim. -- Do not use manual kubectl rollout, image patching, or ad hoc production repair. - -## Definition of Done -- The Quote lifecycle page has a stable selected or pinned quote investigator separate from the rolling table rows. -- Selecting an `Awaiting executor` row lets the operator continue following that quote after the table is paused, resumed, filtered, or updated. -- A selected quote can be refreshed or auto-refreshed from durable evidence even when it is no longer present in `recent_lifecycle_rows`. -- Lookup by `quote_id`, `decision_id`, or `command_id` returns the same normalized lifecycle shape used by the table, including stage timestamps, reason text, timing, command, execution result, and outcome fields when present. -- Problem-state filters make missed quote rows easy to isolate without hiding the selected quote investigation. -- Rows with missing old fields render as unavailable instead of crashing or disappearing. -- Bug regression coverage proves: - - a selected quote remains inspectable after it leaves the recent live list - - an `Awaiting executor` row can later refresh into a terminal executor or relay result - - lookup by quote, decision, and command identifiers uses durable evidence and does not rely only on the current client-side recent rows -- Targeted dashboard tests pass. -- Full `npm test` passes. -- The operator dashboard bundle builds. -- The planning and implementation commits include `Proof:`, `Assumptions:`, and `Still fake:`. -- If tests pass, deploy only through the repo push workflow and collect live evidence: - - repo-owned deployments are on the new image - - Quote lifecycle still receives live rows - - at least one durable quote lookup returns a lifecycle row - - a missed or pending quote can be inspected by identifier after it is not relied on as a visible recent row - -## Failure Conditions -- Pause still freezes the only available evidence for a selected quote. -- A selected quote cannot be found once it leaves the rolling recent table. -- The lookup path searches only the browser's current rows instead of durable history. -- The UI improves labels but still cannot answer what happened after `Awaiting executor`. -- Missed-quote filters hide the selected investigation or make old rows unreadable. -- The implementation changes trading behavior or strategy economics. -- No regression test covers the row-follow-up bug. - -## Real Versus Fake -- Real in scope: dashboard investigation backed by durable quote, decision, command, executor result, and outcome rows already stored by repo-owned services. -- Still fake or incomplete: venue-native final fill truth, fee-aware realized PnL, broader quote analytics workbench, and historical aggregate drilldowns beyond the existing retained lifecycle detail and rollups. +No approved implementation proof is active yet. diff --git a/archive/implementation/20260612T174316Z-quote-lifecycle-investigator-and-missed-quote-follow-up-implementation.md b/archive/implementation/20260612T174316Z-quote-lifecycle-investigator-and-missed-quote-follow-up-implementation.md new file mode 100644 index 0000000..2a8b793 --- /dev/null +++ b/archive/implementation/20260612T174316Z-quote-lifecycle-investigator-and-missed-quote-follow-up-implementation.md @@ -0,0 +1,190 @@ +# 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. diff --git a/archive/implementation/20260612T174316Z-quote-lifecycle-investigator-and-missed-quote-follow-up-proof.md b/archive/implementation/20260612T174316Z-quote-lifecycle-investigator-and-missed-quote-follow-up-proof.md new file mode 100644 index 0000000..b5ddb12 --- /dev/null +++ b/archive/implementation/20260612T174316Z-quote-lifecycle-investigator-and-missed-quote-follow-up-proof.md @@ -0,0 +1,80 @@ +# Implementation Proof: Quote lifecycle investigator and missed quote follow-up + +Status: open +Opened: 2026-06-12 + +## Hypothesis +If the operator dashboard turns the quote lifecycle table into a durable quote investigator, an operator can pause or filter the live quote list, select an `Awaiting executor` or otherwise missed quote, and continue following that exact quote through command, executor result, relay failure, outcome, or unresolved state even after the rolling live table moves on. + +## Problem Evidence +- The current Quote lifecycle page is a rolling live table of recent rows. +- Pausing freezes the displayed table snapshot, including stale `Awaiting executor` evidence. +- When live updates resume, the quote can leave the recent window and become hard to find again. +- The existing expandable row explains the lifecycle only while the row remains in the rendered recent set. +- This prevents practical investigation of missed quotes such as commands that later become `quote_not_found_or_finished`, `verifier_salt_unavailable`, stale command rejects, or successful submissions. + +## Scope +- Improve the existing `Quote lifecycle` dashboard view, not a new dashboard product area. +- Add a durable quote lookup path by `quote_id`, `decision_id`, or `command_id` using existing history tables. +- Add a selected or pinned quote investigator that remains visible independently from the rolling table rows. +- Make pause freeze table ordering only; the selected quote investigation must still refresh from durable evidence. +- Add search or lookup controls so a quote can be found again after it leaves the recent table. +- Add filters for investigation states that matter to missed quotes: + - awaiting executor + - approved but command missing + - blocked before submit + - submission failed + - quote not found or finished + - strategy rejected + - submitted or awaiting outcome +- Improve the selected quote detail so `Awaiting executor` clearly shows: + - command id and command timestamp + - elapsed time since command + - whether an executor result is now stored + - relay result or block reason if present + - next expected stage when still unresolved +- Preserve old executor result and lifecycle rows as readable when newer timing or result fields are missing. +- Keep the implementation read-side and dashboard-only unless a small shared lifecycle normalizer change is required. + +## Non-goals +- Do not change strategy selection, pricing, edge thresholds, notional limits, inventory checks, arming, signer identity, or pair enablement. +- Do not skip quotes or alter executor/relay response behavior. +- Do not add active pair, edge, notional, latency, response-policy, or retention environment variables. +- Do not add a new retention policy or new long-term analytics store in this turn. +- Do not build the full remaining analytics workbench: quote volume windows, size-bucket distributions, oracle-deviation views, and matched-only PnL analytics remain backlog work. +- Do not claim submitted quote responses are completed trades unless durable outcome and settlement evidence support that claim. +- Do not use manual kubectl rollout, image patching, or ad hoc production repair. + +## Definition of Done +- The Quote lifecycle page has a stable selected or pinned quote investigator separate from the rolling table rows. +- Selecting an `Awaiting executor` row lets the operator continue following that quote after the table is paused, resumed, filtered, or updated. +- A selected quote can be refreshed or auto-refreshed from durable evidence even when it is no longer present in `recent_lifecycle_rows`. +- Lookup by `quote_id`, `decision_id`, or `command_id` returns the same normalized lifecycle shape used by the table, including stage timestamps, reason text, timing, command, execution result, and outcome fields when present. +- Problem-state filters make missed quote rows easy to isolate without hiding the selected quote investigation. +- Rows with missing old fields render as unavailable instead of crashing or disappearing. +- Bug regression coverage proves: + - a selected quote remains inspectable after it leaves the recent live list + - an `Awaiting executor` row can later refresh into a terminal executor or relay result + - lookup by quote, decision, and command identifiers uses durable evidence and does not rely only on the current client-side recent rows +- Targeted dashboard tests pass. +- Full `npm test` passes. +- The operator dashboard bundle builds. +- The planning and implementation commits include `Proof:`, `Assumptions:`, and `Still fake:`. +- If tests pass, deploy only through the repo push workflow and collect live evidence: + - repo-owned deployments are on the new image + - Quote lifecycle still receives live rows + - at least one durable quote lookup returns a lifecycle row + - a missed or pending quote can be inspected by identifier after it is not relied on as a visible recent row + +## Failure Conditions +- Pause still freezes the only available evidence for a selected quote. +- A selected quote cannot be found once it leaves the rolling recent table. +- The lookup path searches only the browser's current rows instead of durable history. +- The UI improves labels but still cannot answer what happened after `Awaiting executor`. +- Missed-quote filters hide the selected investigation or make old rows unreadable. +- The implementation changes trading behavior or strategy economics. +- No regression test covers the row-follow-up bug. + +## Real Versus Fake +- Real in scope: dashboard investigation backed by durable quote, decision, command, executor result, and outcome rows already stored by repo-owned services. +- Still fake or incomplete: venue-native final fill truth, fee-aware realized PnL, broader quote analytics workbench, and historical aggregate drilldowns beyond the existing retained lifecycle detail and rollups.