Open implementation turn: Persisted quote statistics

Proof: Establish the approved persisted quote statistics turn with falsifiable rollup, API, dashboard, and validation requirements.

Assumptions: The requested statistics are the active implementation scope, and broader analytics from the old backlog item remains follow-up work.

Still fake: Planning docs only; no persisted statistics, API, dashboard, tests, deployment, or live evidence are implemented by this commit.
This commit is contained in:
philipp 2026-06-12 19:45:24 +02:00
parent 8805282f59
commit 893617c30d
4 changed files with 167 additions and 7 deletions

View file

@ -46,3 +46,4 @@ Legacy note:
- 2026-06-06: opened implementation turn `quote-lifecycle-retention-and-analytics-rollups` from backlog items none. - 2026-06-06: opened implementation turn `quote-lifecycle-retention-and-analytics-rollups` from backlog items none.
- 2026-06-12: opened implementation turn `verifier-salt-hot-path-removal-and-executor-queue-guardrails` from backlog items none. - 2026-06-12: opened implementation turn `verifier-salt-hot-path-removal-and-executor-queue-guardrails` from backlog items none.
- 2026-06-12: opened implementation turn `quote-lifecycle-investigator-and-missed-quote-follow-up` from backlog items I012; remaining broad analytics-workbench scope was re-added as I017. - 2026-06-12: opened implementation turn `quote-lifecycle-investigator-and-missed-quote-follow-up` from backlog items I012; remaining broad analytics-workbench scope was re-added as I017.
- 2026-06-12: opened implementation turn `persisted-quote-statistics-rollups-and-live-counters` from backlog items I017.

View file

@ -20,7 +20,7 @@ Rules:
- [I013] Benchmark and PnL analytics: compare trade PnL versus mark-to-market, all-BTC hold, all-EURe hold, passive 50/50 hold, and hindsight trade quality against later benchmarks. - [I013] Benchmark and PnL analytics: compare trade PnL versus mark-to-market, all-BTC hold, all-EURe hold, passive 50/50 hold, and hindsight trade quality against later benchmarks.
- [I016] (soon) Treasury cashflow and fee ledger: durably record deposits, withdrawals, bridge or network costs, and other non-trade cashflows so dashboard profit can move from mark-to-market to true net PnL. tags=pnl,fees,treasury - [I016] (soon) Treasury cashflow and fee ledger: durably record deposits, withdrawals, bridge or network costs, and other non-trade cashflows so dashboard profit can move from mark-to-market to true net PnL. tags=pnl,fees,treasury
- [I017] (soon) Remaining quote analytics workbench beyond lifecycle investigation: quote count and volume windows, size-bucket distributions, oracle-deviation views, matched-only filters, and broader execution analytics. tags=analytics,dashboard,quotes - [I017] (soon) Remaining quote analytics workbench beyond persisted state rollups: volume windows, size-bucket distributions, oracle-deviation views, matched-only filters, and broader execution analytics. tags=analytics,dashboard,quotes
## Research Candidates ## Research Candidates
- [R001] Compare Kraken and CoinGecko drift and freshness for the assets needed to price the active pair. - [R001] Compare Kraken and CoinGecko drift and freshness for the assets needed to price the active pair.
- [R002] Test whether the active pair's implied rate diverges from external reference prices enough to justify execution after a simple 2% gross threshold. - [R002] Test whether the active pair's implied rate diverges from external reference prices enough to justify execution after a simple 2% gross threshold.

View file

@ -1,5 +1,95 @@
# Implementation Turn # Implementation Turn: Persisted quote statistics rollups and live counters
Status: idle Status: open
Opened: 2026-06-12
No approved implementation turn is active yet. ## Goal
Persist durable quote lifecycle statistics for 5-minute, hourly, daily, weekly, monthly, and all-time windows so operators can see unique quote totals and outcome-state counts from the same history used by live lifecycle evidence.
## Selected backlog items
- [I017] Persisted quote-state rollups only. The broader quote analytics workbench scope from the original backlog item has been re-added to backlog for a later turn.
## Hard Constraints
- Do not change strategy selection, pricing, edge thresholds, notional limits, inventory checks, arming, signer identity, pair enablement, executor behavior, relay behavior, or quote skipping behavior.
- Do not add active pair, edge, notional, latency, response-policy, or retention environment variables.
- Do not add a storage system or retention policy. Use existing PostgreSQL history and repo-owned workflow.
- Preserve old lifecycle and executor-result rows as readable; missing fields become `unavailable`.
- Bug fixes require regression tests.
- No manual `kubectl` rollout, image patching, or cluster repair. Deploy only through the repo workflow.
- Do not stage or revert unrelated dirty worktree files.
## Implementation Plan
### 1. Inspect Current Paths
- Read the current quote lifecycle row derivation, durable lookup, reducer, dashboard routes, static dashboard components, existing rollup or retention loaders, migrations/schema setup, and related tests.
- Confirm whether an existing quote lifecycle rollup table can store the requested state buckets. Prefer extending existing rollup machinery when it is compatible; otherwise add one narrow PostgreSQL aggregate table dedicated to quote lifecycle statistics.
### 2. Classification Contract
- Build a reusable lifecycle statistics classifier on normalized durable lifecycle rows.
- Assign each quote to one latest state bucket per recompute:
- `success`: durable completed/success result or settlement evidence exists
- `not_filled`: durable terminal not-filled or expired outcome exists
- `submission_failed`: executor or relay submission failed
- `submitted_no_reply`: command was submitted or relay-accepted, but no durable terminal reply is known
- `awaiting_executor`: strategy approved and command/executor evidence is still missing
- `blocked_before_submit`: executor or safety gate blocked before venue submission
- `rejected_by_strategy`: strategy rejected the quote before execution
- `unavailable`: old, partial, or malformed evidence cannot be classified safely
- Terminal states must take precedence over intermediate states when multiple history rows exist for the same quote.
- Count distinct `quote_id` values. Track missing quote identifiers separately as unavailable evidence; do not fabricate identifiers.
- Use the quote's first durable lifecycle timestamp as its window timestamp. If the first timestamp is missing, use the earliest available durable stage timestamp and mark timestamp provenance as unavailable in testable code.
### 3. Persistence
- Add or extend a PostgreSQL-backed persisted rollup with:
- grain: `all_time`, `month`, `week`, `day`, `hour`, `five_minute`
- UTC `window_start` and `window_end` for windowed grains
- unique quote total
- missing identifier count
- state bucket counts
- computed timestamp
- Keep the storage idempotent with a deterministic key per grain/window and upsert semantics.
- Recompute from existing durable history rather than appending event deltas that can drift.
- Wire recomputation into the existing lifecycle history or dashboard maintenance path so live systems persist updated stats without requiring manual scripts.
- Do not introduce new retention knobs or background services unless an existing repo-owned process already performs the relevant maintenance.
### 4. Dashboard API
- Add an authenticated operator-dashboard endpoint for quote lifecycle statistics.
- Return all-time totals plus recent windows for the requested grains. Clamp limits server-side and preserve missing or unavailable fields in the response.
- Include enough metadata for the UI to label UTC windows and live/update freshness without implying unavailable truth is known.
### 5. Dashboard UI
- Add a statistics surface to the Quote lifecycle page or its existing operator context.
- Provide controls for `5m`, `hour`, `day`, `week`, `month`, and `all-time`.
- Display unique quote totals and state bucket counts for the selected grain.
- Show live counters for current windows and all-time totals that update from the live dashboard stream.
- Pausing the recent lifecycle table must not freeze the statistics surface or live counters.
- Use existing component, style, and reducer patterns; keep controls dense and operational rather than marketing-style.
### 6. Tests
- Add focused classifier/window tests for state precedence, UTC boundaries, Monday UTC weeks, missing IDs, missing timestamps, and old-field compatibility.
- Add persistence tests proving idempotent upsert/recompute and all-time totals.
- Add route tests proving authentication and persisted response shape.
- Add reducer/UI tests proving live counters update while the recent table is paused.
- Add regression coverage for a quote that begins as `submitted_no_reply` or `awaiting_executor`, leaves the live recent table, and later refreshes into `submission_failed`, `not_filled`, or `success` through durable history.
### 7. Validation And Deployment
- Run targeted tests covering the changed backend and dashboard surfaces.
- Run full `npm test`.
- Build the dashboard bundle.
- Commit with required `Proof:`, `Assumptions:`, and `Still fake:` body.
- Push only after tests and build pass.
- Let the repo workflow deploy the new image.
- Collect live evidence:
- deployed image digest or tag includes this commit
- lifecycle live rows still flow
- statistics endpoint returns real persisted rows
- live counters move without requiring the quote to remain visible in the rolling table
## Assumptions To Verify While Coding
- Existing lifecycle history has a stable enough `quote_id` for unique quote counting. Rows without one are counted as unavailable evidence, not invented unique quotes.
- Existing durable history has enough timestamps to assign quotes to UTC windows. Missing timestamps remain unavailable rather than blocking all statistics.
- Current lifecycle lookup and row derivation already encode most state distinctions; the statistics classifier should reuse that truth instead of creating a competing interpretation.
## Still Fake Or Deferred
- Fee-aware PnL, treasury cashflow, benchmark markout, oracle-deviation, size distribution, and matched-only analytics are not part of this turn.
- Statistics can only be as complete as the already-retained quote lifecycle/history tables. Already-pruned detail cannot be reconstructed.

View file

@ -1,5 +1,74 @@
# Implementation Proof # Implementation Proof: Persisted quote statistics rollups and live counters
Status: idle Status: open
Opened: 2026-06-12
No approved implementation proof is active yet. ## Hypothesis
Persisted quote lifecycle statistics over 5-minute, hourly, daily, weekly, monthly, and all-time windows will let the operator answer "how many quotes did we see and where did they end up?" without relying on the rolling dashboard table or browser memory.
## Scope
- This turn implements the persisted quote-state rollup part of the selected analytics backlog item. The broader analytics workbench work, including quote volume distribution, size buckets, oracle-deviation views, matched-only filters, and broader execution analytics, remains backlog follow-up scope.
- Use the existing durable quote lifecycle/history data and existing PostgreSQL storage. Do not add a new storage system, retention policy, or long-running external job outside the repo-owned workflow.
- Persist aggregates for these grains:
- `all_time`
- `month`
- `week`
- `day`
- `hour`
- `five_minute`
- A quote is assigned to a time-window by its first observed durable lifecycle timestamp in UTC. Weekly windows start on Monday UTC. The quote's state bucket may refresh later when new durable executor, relay, or settlement evidence arrives.
- Count unique quotes by `quote_id` when present. Rows without a durable quote identifier must remain visible as `unavailable` or `missing_identifier_count`; the implementation must not invent fake unique identifiers to inflate quote totals.
- Persist and expose at least these state buckets:
- `rejected_by_strategy`
- `awaiting_executor`
- `submission_failed`
- `submitted_no_reply`
- `success`
- `not_filled`
- `blocked_before_submit`
- `unavailable`
- Preserve old lifecycle and executor-result rows. Missing fields should count as unavailable instead of crashing or silently disappearing.
- Expose authenticated dashboard access to the persisted statistics and render them in the operator dashboard with live counts that continue updating independently of any paused recent lifecycle table.
## Non-goals
- Do not change strategy selection, pricing, edge thresholds, notional limits, inventory checks, arming, signer identity, pair enablement, executor behavior, relay behavior, or quote skipping behavior.
- Do not add active pair, edge, notional, latency, response-policy, or retention environment variables.
- Do not add PnL, fee-aware accounting, treasury cashflow, oracle-deviation analysis, size-bucket analytics, matched-only filters, or strategy tuning in this turn.
- Do not manually patch images, roll deployments, or repair the cluster outside the repo workflow.
- Do not rewrite `THESIS.md`.
## Definition of Done
- Existing quote lifecycle/history tables can be rolled up into persisted statistics for all requested grains and all-time totals.
- Aggregation is idempotent: recomputing the same history does not double-count quotes or duplicate windows.
- Each counted quote lands in exactly one state bucket per grain window, with terminal evidence taking precedence over intermediate states.
- The dashboard API returns authenticated persisted statistics, including all-time totals and recent windows.
- The dashboard UI shows the statistics, has controls for the requested grains, and live counts keep changing while the recent quote table is paused.
- Regression tests prove:
- unique quote dedupe across lifecycle, decision, command, executor, and relay evidence
- `submitted_no_reply` does not become `success` without durable success/settlement evidence
- a later executor or relay result refreshes the persisted bucket for the quote's original time window
- old or missing fields are represented as unavailable rather than throwing or hiding rows
- all requested window boundaries are UTC and weekly windows start Monday UTC
- all-time totals match the same classified quote set as the windowed stats
- Run targeted tests, full `npm test`, and build the dashboard bundle.
- Commit with `Proof:`, `Assumptions:`, and `Still fake:` in the commit body.
- Push and deploy only after tests pass, then collect live evidence for:
- new image from the repo workflow
- quote lifecycle live rows still flowing
- persisted statistics endpoint returning real rows
- live dashboard counts moving without relying on recent-table visibility
## Failure Conditions
- Statistics are derived only from browser state, recent WebSocket rows, or mock fixtures.
- A single quote can be counted more than once in the same grain window.
- Submitted-but-unanswered quotes are mislabeled as successful.
- Missing old fields crash aggregation or make rows vanish.
- The implementation changes trading behavior, execution behavior, pair enablement, thresholds, notional limits, inventory safety, or arming behavior.
- Deployment requires manual cluster image patching or ad hoc rollout intervention.
## What Is Real
- The proof is about durable aggregate truth from the same stored quote lifecycle evidence used by operator investigation and live lifecycle rows.
## Still Fake Or Out Of Scope
- Final venue-native fill truth remains limited to the durable evidence already present in the system.
- Fee-aware PnL, cashflow, benchmark markouts, quote size distributions, oracle-deviation analysis, and matched-only analytics remain future turns.