Compare commits

..

No commits in common. "208be20a1c21808e3ddead5a04d3dfdd246cad7a" and "715a0aec506bc82a3c7b73396efb0e3c5f20804f" have entirely different histories.

6 changed files with 424 additions and 736 deletions

View file

@ -12,7 +12,6 @@ Legacy note:
- 2026-04-07: `operator-dashboard-foundation-funds-desk-and-operator-controls` closed with status `passed`. A real operator dashboard shipped with authenticated REST and WebSocket surfaces, truthful funded-capital profitability, live quote and trade visibility, and safe operator controls over the BTC/EURe system. - 2026-04-07: `operator-dashboard-foundation-funds-desk-and-operator-controls` closed with status `passed`. A real operator dashboard shipped with authenticated REST and WebSocket surfaces, truthful funded-capital profitability, live quote and trade visibility, and safe operator controls over the BTC/EURe system.
- 2026-04-08: `cow-protocol-intent-based-venue-integration` closed with status `paused`. The CoW venue integration turn is paused after cluster investigation showed a real NEAR Intents ingest outage exposed a larger observability gap: the dashboard did not escalate stale quote flow or disconnected websocket clients, so runtime health and alerting need to be strengthened before adding a second venue. - 2026-04-08: `cow-protocol-intent-based-venue-integration` closed with status `paused`. The CoW venue integration turn is paused after cluster investigation showed a real NEAR Intents ingest outage exposed a larger observability gap: the dashboard did not escalate stale quote flow or disconnected websocket clients, so runtime health and alerting need to be strengthened before adding a second venue.
- 2026-04-08: `runtime-health-sentinel-alert-routing-and-anomaly-detection` closed with status `passed`. Runtime health is now sentinel-owned, stale truth no longer renders healthy, alert delivery and safe containment exist, and deployment automation rolls all repo-owned services from push. - 2026-04-08: `runtime-health-sentinel-alert-routing-and-anomaly-detection` closed with status `passed`. Runtime health is now sentinel-owned, stale truth no longer renders healthy, alert delivery and safe containment exist, and deployment automation rolls all repo-owned services from push.
- 2026-04-09: `quote-lifecycle-truth-and-execution-explanation` closed with status `passed`. Live operator surfaces now derive quote lifecycle from durable evidence, distinguish strategy rejection from executor blocking and submission, expose copyable quote traces, and no longer overclaim submission as completion or asset movement.
## Research Turns ## Research Turns
## Planning Events ## Planning Events
@ -26,4 +25,3 @@ Legacy note:
- 2026-04-07: opened implementation turn `cow-protocol-intent-based-venue-integration` from backlog items I019. - 2026-04-07: opened implementation turn `cow-protocol-intent-based-venue-integration` from backlog items I019.
- 2026-04-08: opened implementation turn `runtime-health-sentinel-alert-routing-and-anomaly-detection` from backlog items I020. - 2026-04-08: opened implementation turn `runtime-health-sentinel-alert-routing-and-anomaly-detection` from backlog items I020.
- 2026-04-08: opened implementation turn `quote-lifecycle-truth-and-execution-explanation` from backlog items I021. - 2026-04-08: opened implementation turn `quote-lifecycle-truth-and-execution-explanation` from backlog items I021.
- 2026-04-09: opened implementation turn `execution-outcome-truth-and-settled-attribution` from backlog items I017, I018.

View file

@ -22,6 +22,8 @@ Rules:
- [I015] (soon) Benchmark-aware strategy thresholds and inventory-skewed fees: compare live inventory against deposit-time hold and target BTC/EURe mix before quoting away preferred inventory. tags=strategy,inventory,pnl - [I015] (soon) Benchmark-aware strategy thresholds and inventory-skewed fees: compare live inventory against deposit-time hold and target BTC/EURe mix before quoting away preferred inventory. tags=strategy,inventory,pnl
- [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) Per-trade realized attribution: link each successful trade to actual settled inventory deltas and attributable costs so the system can report realized net contribution per trade instead of only expected edge. tags=trades,pnl,settlement
- [I018] (later) Quote-to-outcome and markout analytics: link quote, response, decision, execution result, and settlement, then store later reference-price markouts to measure adverse selection and quote quality. tags=quotes,analytics,markout
## 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,174 +1,306 @@
# Implementation Turn: execution outcome truth and settled attribution # Implementation Turn: quote lifecycle truth and execution explanation
Status: open Status: open
Opened: 2026-04-09 Opened: 2026-04-09
## Goal ## Goal
Make the live BTC/EURe quote path more real by durably linking submission, downstream outcome, and settled inventory attribution so the dashboard can distinguish completion from submission and show real post-trade movement where available. Replace ambiguous quote and decision wording with a truthful per-quote lifecycle that tells the operator exactly why a quote was filtered, rejected, blocked, submitted, failed, not filled, or completed.
## Selected backlog items ## Selected backlog items
- [I017] Per-trade realized attribution: link each successful trade to actual settled inventory deltas and attributable costs so the system can report realized net contribution per trade instead of only expected edge. - [I021] Quote lifecycle truth and execution explanation: replace ambiguous dashboard verdicts with a per-quote state machine that shows exactly why a quote was filtered, rejected, blocked, submitted, not filled, or executed, with durable reason codes and operator-facing traceability.
- [I018] Quote-to-outcome and markout analytics: link quote, response, decision, execution result, and settlement, then store later reference-price markouts to measure adverse selection and quote quality.
## Design rules ## Design rules
- Treat downstream outcome and settlement truth as part of the same shared evidence path, not separate dashboard decoration. - Treat quote lifecycle as product truth, not UI decoration.
- Preserve the current turns semantic boundary: submission is still non-terminal. - Strategy verdict is not the final operator answer.
- Store explicit linkage and attribution records instead of recomputing ad hoc joins differently across pages. - Prefer one explicit lifecycle derivation path shared by backend and dashboard over ad hoc page-specific wording.
- If a linkage is heuristic, store the heuristic and expose uncertainty. - Do not invent downstream certainty where durable evidence is absent.
- Keep the first implementation narrow to the active pair and current venue. - Remove `Actionable` completely from operator-facing copy.
- Do not use stronger operator words than the durable evidence supports.
- Fix semantic bugs by changing both the code and the tests that encoded the wrong assumption.
## Problem statement for this turn ## Problem statement for this turn
The repository now explains why a quote was rejected, blocked, or submitted, but it still does not fully explain what happened after submission: The current dashboard still forces operators to infer too much:
- terminal outcome truth is absent or disconnected - `Actionable` does not say whether a command was emitted or submitted
- recent submission tables are still quote-term oriented rather than settlement oriented - the Strategy page mixes strategy and execution truth
- completed and realized labels cannot yet be proven from repo-owned durable records - executor-rejected rows are not clearly distinguishable from strategy-rejected rows
- later analytics such as markout and realized contribution have no canonical per-quote linkage record - quote ids are truncated and awkward to use during debugging
This turn must therefore improve: The repo already stores enough of the real lifecycle to do better:
- downstream outcome ingestion or linkage - quote id
- quote-to-outcome storage - decision id
- settlement attribution storage - emitted command id
- operator rendering of completed versus submission-only rows - execution result status and result code
## Required evidence model The recent submission-versus-trade bug showed the broader prevention gap:
Add one repo-owned quote outcome and attribution model with at least: - wrong semantics were encoded in backend query names
- `quote_id` - the dashboard rendered stronger claims than the evidence supported
- `decision_id` - tests asserted the wrong meaning instead of protecting the truth
- `command_id`
- `execution_result_status`
- `outcome_status`
- `outcome_observed_at`
- `outcome_source`
- `attribution_status`
- `attributed_inventory_delta`
- `attribution_method`
- `markout_reference_price` where implemented
Suggested vocabulary: The turn therefore needs to improve:
- outcome states: - lifecycle derivation
- `submitted` - durable reason mapping
- `awaiting_outcome` - recent-row rendering
- `not_filled` - trace affordances
- `completed`
- attribution states: ## Lifecycle model for this turn
- `unattributed` Implement one repo-owned lifecycle derivation for recent rows, using durable evidence in this order:
- `heuristic_match`
- `linked_settlement` 1. Quote observed
2. Strategy evaluated
3. Command emitted or not emitted
4. Executor result observed or absent
5. Venue downstream outcome when available
The first mandatory states are:
- `Filtered`
- `Rejected`
- `Blocked`
- `Submitted`
- `Failed`
- `Awaiting outcome`
- `Completed`
These states must become the repo-owned evidence vocabulary for operator surfaces and summaries.
Suggested meanings:
- `Filtered`
quote never entered the active trade path or was excluded before strategy decision
- `Rejected`
strategy evaluated the quote and decided not to trade
- `Blocked`
strategy approved or emitted a command, but execution did not proceed due to control state or another repo-owned gate
- `Submitted`
executor accepted the command and successfully submitted a quote response
- `Failed`
execution submission failed technically
- `Awaiting outcome`
submitted to venue, but no later durable terminal venue outcome exists yet
- `Completed`
durable evidence shows the trade completed successfully
Do not show states we cannot support yet for a given row.
## Reason-code model
For each lifecycle state, map durable payload fields to a small operator reason taxonomy.
Examples:
- strategy reason codes:
- unsupported_pair
- below_edge_threshold
- inventory_unavailable
- stale_reference_price
- executor reason codes:
- executor_disarmed
- executor_paused
- submission_failed
- quote_response_ok
- downstream outcome reasons if available:
- expired
- not_filled
- completed
If the exact reason is missing:
- expose `reason_unknown`
- keep the row truthful instead of synthesizing an explanation
## Semantic guardrails for this turn
### 1. Ban overloaded certainty words unless evidence justifies them
Review and remove or rename operator-facing and backend terms such as:
- `successfulTradeCount`
- `lastSuccessfulTradeAt`
- `loadSuccessfulTradesPage`
- `trade_asset_changes`
- any UI label implying trade completion, realized asset movement, or PnL attribution from mere submission evidence
Allowed wording must be tied to the strongest durable evidence actually present.
### 2. Encode semantic invariants in code and tests
Add explicit checks and regression coverage for:
- `submitted != completed`
- `submitted != realized asset delta`
- executor blocking != strategy rejection
- no UI label may claim trade completion from submission-only evidence
Negative tests are required, not just positive-path tests.
## Backend changes ## Backend changes
### 1. Add durable outcome linkage ### 1. Add a lifecycle derivation helper
- inspect available downstream event sources, solver relay data, inventory movement evidence, and existing history tables Create or extend a backend module that derives quote lifecycle from:
- add a durable record or derived snapshot that links a submitted quote to later terminal outcome when possible - recent trade decisions
- preserve source timestamps and raw evidence pointers - recent execution results
- later terminal records only where they are real
- any available quote-status or venue result surfaces
### 2. Add durable settlement attribution It should emit a normalized row object with:
- link completed quote outcomes to later inventory movement for the active assets - `quote_id`
- store both raw units and formatted operator values - `decision_id`
- track whether the attribution is exact or heuristic - `command_id`
- do not report net realized contribution unless costs are explicitly present - `pair`
- `direction`
- `lifecycle_state`
- `lifecycle_label`
- `reason_code`
- `reason_text`
- timestamps for the latest known stage
- stage details for tooltips or drilldown
### 3. Extend dashboard bootstrap models ### 2. Join decision and execution truth explicitly
- expose recent quote outcome rows with terminal evidence where available The backend should no longer leave the frontend to infer execution from isolated tables.
- expose settled attribution separately from submitted quote terms
- ensure summary metrics count completed outcomes and submission-only rows separately
### 4. Prepare markout support on the same linkage path For each recent quote/decision row:
- if implemented in this turn, compute later reference-price markout from the linked quote or completion timestamp - attach the matching execution result by `command_id`, `decision_id`, or `quote_id`
- store it in a way that cannot be confused with realized settlement contribution - attach terminal completion or non-fill evidence only where it is genuinely available
- expose whether the row is strategy-only, strategy-plus-command, or strategy-plus-execution
## UI changes As part of this phase, rename misleading backend aggregation helpers and payload fields where practical so code meaning matches evidence meaning.
### 3. Preserve operator drilldown identifiers
Ensure the bootstrap payload exposes:
- full quote id
- full decision id
- full command id
Avoid requiring the frontend to reconstruct or guess identifiers from formatted strings.
## Dashboard changes
### 4. Remove forbidden language
Remove `Actionable` from:
- Strategy page tables
- any lifecycle badge or verdict cell
- any supporting labels or legends
Replace it with explicit state labels driven by lifecycle derivation.
Also remove or rename any remaining wording that presents submission evidence as trade completion or realized asset movement.
### 5. Make recent rows self-explanatory
For each row, render:
- primary lifecycle state
- secondary reason text
- quote id with copy action
- command id if emitted
- timestamps
The operator should be able to scan rows and answer:
- why no trade happened
- whether the system tried to trade
- whether failure was strategic, operational, or downstream
### 6. Add trace affordances
At minimum:
- copy button for quote id
- avoid over-truncating ids without recovery path
- show linked ids in a dedicated trace column or expanded detail panel
If the row layout gets crowded, prefer an expandable detail tray over hiding identifiers.
## Page-level application
### Strategy page ### Strategy page
- extend lifecycle rows so submitted paths can become `Awaiting outcome`, `Not filled`, or `Completed` This page should become the primary recent quote-decision-execution lifecycle surface.
- show linked outcome reason and settlement attribution state
- keep quote, decision, and command trace ids visible
### Funds page It should show:
- separate: - the latest recent rows for the active pair
- recent submission terms - lifecycle state rather than strategy-only verdict
- recent settled attribution - explicit explanation text
- completed outcome ledger
- if no settled attribution exists yet for a completed row, say that plainly
### Summary language If a strategy-only summary remains, it must be visually separate from per-quote lifecycle truth.
- introduce distinct labels for:
- recent submissions
- recent completed outcomes
- recent settled attributions
- never reuse one metric for all three concepts
## Edge cases ### Related quote surfaces
- submitted row with no later evidence: Inspect quote and system surfaces for similar ambiguity and align the wording if they expose the same concepts.
Do not let one page say `Submitted` while another page still says `Actionable` for the same row.
Do not let one page say `trade` while another page only has `submitted` evidence for the same row.
## Data and state edge cases
- Strategy decision exists, no command emitted:
render as `Rejected` with strategy reason
- Command emitted, no execution result yet:
render as `Blocked` or `Awaiting executor` only if that distinction is durably supportable; otherwise use a truthful pending label
- Execution result `executor_disarmed`:
render as `Blocked` with reason `executor disarmed`
- Execution result `submission_failed`:
render as `Failed`
- Execution result `submitted`:
render as `Submitted` or `Awaiting outcome` render as `Submitted` or `Awaiting outcome`
- explicit expiry or non-fill evidence: - Successful trade summary exists but no explicit per-quote completion event:
render as `Not filled` only promote to `Completed` where the durable linkage is real
- completed outcome with no attributable inventory delta yet: - Submission evidence appears in profitability or summary widgets:
render completion truthfully, but mark attribution as missing rename and constrain those widgets so they do not imply realized trade truth
- inventory movement with no unambiguous quote match:
keep unattributed and do not silently assign
- multiple near-simultaneous quotes in the same direction:
require explicit or recorded heuristic linkage before claiming settlement
## Concrete implementation order ## Concrete implementation order
### Phase 1. Discover and define outcome sources ### Phase 1. Define lifecycle derivation
- inspect current relay, executor, and inventory evidence - inspect current durable decision and execution payloads
- document what fields can carry downstream outcome and settlement linkage - write the normalized lifecycle state mapping
- define exact versus heuristic attribution rules - define forbidden and allowed operator labels
- list misleading backend and UI names that must be changed
- define the semantic invariant tests up front
### Phase 2. Implement durable outcome and attribution records ### Phase 2. Implement backend aggregation
- add storage or derived records for linked outcomes - derive unified recent lifecycle rows
- add storage or derived records for settlement attribution - expose full identifiers and reason codes
- preserve raw references and timestamps - keep old consumers working until the frontend is switched
- rename misleading submission-as-trade helpers and summary fields where touched
### Phase 3. Update dashboard aggregation ### Phase 3. Update Strategy page rendering
- join recent lifecycle rows to outcome and attribution records - replace verdict column with lifecycle state
- split summary metrics and ledgers by evidence strength - add reason text
- keep submission-only rows clearly non-terminal - add quote-id copy affordance
- surface command id and execution state where relevant
### Phase 4. Validate on live data ### Phase 4. Tighten wording and consistency
- prove at least one recent row remains submission-only - remove `Actionable`
- prove blocked and rejected rows remain distinct - align supporting labels
- prove a completed or non-fill row appears only with durable linked evidence - ensure blocked vs rejected vs submitted are clearly distinct
- prove settled attribution is shown only when actual linked movement exists - ensure submitted vs completed vs realized asset movement are clearly distinct
### Phase 5. Validate with live recent rows
- verify a row rejected due to executor disarmed renders as blocked with reason
- verify a submitted row renders as submitted
- verify quote ids can be copied and used for tracing
- verify no submission-only row is rendered as a trade, completion, or realized asset delta
## Test plan ## Test plan
- unit tests for outcome linkage: - unit tests for lifecycle derivation from:
- submitted with no outcome - strategy-rejected rows
- submitted with non-fill outcome - executor-disarmed rows
- submitted with completed outcome - submission-failed rows
- unit tests for attribution: - submitted rows
- completed with linked settlement - unit tests for semantic invariants:
- completed without settlement yet - submitted rows must not be counted as completed trades
- ambiguous movement remains unattributed - submission-only rows must not render as asset deltas
- negative semantic tests:
- submission-only rows must not render completion
- markout must not be labeled realized
- quote terms must not be labeled settled asset delta
- dashboard bootstrap tests for: - dashboard bootstrap tests for:
- separated summary metrics - forbidden `Actionable` removal
- completed rows carrying explicit outcome evidence - explicit lifecycle labels
- unattributed rows staying plainly unattributed - reason text rendering
- identifier exposure
- dashboard summary tests for renamed or narrowed submission metrics
- frontend component tests if needed for copy affordance or row rendering logic
No lifecycle ambiguity fix is complete without a regression test proving the old ambiguous wording or overclaim cannot return.
## Validation checklist against the proof ## Validation checklist against the proof
- recent rows separate submitted, awaiting, not-filled, and completed where evidence exists - `Actionable` no longer appears
- completed rows show explicit outcome linkage - strategy approval is visibly distinct from execution submission
- settled attribution is visible and clearly sourced - recent blocked rows explain why they did not trade
- submission-only rows still do not claim completion or realized movement - recent submitted rows show that they were submitted
- remaining uncertainty is named plainly - quote ids are directly usable from the dashboard
- submission-only evidence is no longer rendered as trade completion or asset delta truth
## Failure modes to plan for ## Failure modes to plan for
- linking the wrong inventory movement to a quote - the backend joins rows incorrectly and attributes the wrong execution result
- mistaking inventory rebalance or treasury movement for trade settlement - the UI uses softer wording than the backend lifecycle state
- rendering completed from incomplete venue evidence - older rows lack enough evidence and the UI pretends certainty
- blending markout and realized attribution into one metric - ids are still truncated without a copy or expand path
- introducing hidden heuristics without storing them - misleading legacy names remain in place and create new semantic drift later
## Truth review checklist for this turn ## Truth review checklist for this turn
For every outcome or attribution field: For every operator-facing label, metric, table, or badge touched in this proof:
- what exact durable event or snapshot backs it - what exact durable table or event backs it?
- how is the quote linked to it - what is the strongest claim the evidence supports?
- is the linkage exact or heuristic - what wording would overclaim certainty?
- what wording would overclaim certainty - what negative regression test locks that boundary in?
- what regression test prevents that overclaim from returning

254
PROOF.md
View file

@ -1,138 +1,200 @@
# Implementation Proof: execution outcome truth and settled attribution # Implementation Proof: quote lifecycle truth and execution explanation
Status: open Status: open
Opened: 2026-04-09 Opened: 2026-04-09
## Target outcome ## Target outcome
This turn proves that `unrip` can move recent quote rows past submission-only evidence and into durable downstream outcome truth. This turn proves that `unrip` can explain every quote outcome in operator-visible, durable terms instead of forcing the operator to infer meaning from ambiguous labels.
For the live NEAR Intents BTC/EURe system, the operator must be able to answer: The concrete target is the live NEAR Intents BTC/EURe system:
- was the quote merely submitted - each quote row must expose its current lifecycle state
- did the venue later complete or not fill it - each non-trade outcome must expose the decisive reason code
- what settled inventory delta, if any, was actually observed afterward - execution submission must be distinguishable from strategy approval
- what part of the post-trade change is still inferred versus durably linked - blocked, rejected, submitted, failed, and not-filled paths must be visibly different
- quote identifiers must be directly usable by operators for tracing and support
- operator-facing labels must not overclaim beyond the durable evidence actually stored
## Why this is a meaningful architecture test ## Why this is a meaningful architecture test
The previous turn fixed an overclaiming dashboard, but it also exposed the next hard truth gap: The current operator surface still fails a core thesis requirement:
- `submitted` is now shown truthfully as non-terminal evidence - the Strategy page shows `Actionable`, which does not tell the operator whether a trade was actually submitted
- downstream completion and non-fill states are still mostly absent from durable repo-owned data - an operator looking at one quote cannot answer, at a glance, why it did or did not become a trade
- recent asset-term tables still describe submitted quote terms, not settled inventory truth - quote ids are hidden behind truncation with no direct copy affordance
- realized attribution is still fake because quote response success is not the same thing as completed asset movement - execution truth exists durably in PostgreSQL, but the UI does not surface the lifecycle coherently
That means the system is now honest about the gap, but the gap still exists. This turn is where the shared history path must become more real again. That is not just a copy problem. It is an observability gap in the trading product itself. If the system cannot explain a quote outcome precisely, execution is outrunning observability.
The immediate trigger for this turn is a real semantic failure:
- the dashboard treated `trade_execution_results.status = submitted` as a successful trade
- recent submitted quote terms were rendered as if they were realized asset deltas
- tests passed because that wrong assumption had been encoded into the test suite itself
This turn must therefore fix both the UI and the conditions that allowed the mistake through.
## Hypothesis ## Hypothesis
`unrip` becomes materially more trustworthy if it durably links: `unrip` becomes more trustworthy if quote handling is modeled and rendered as an explicit lifecycle instead of a single strategy verdict:
- quote - strategy evaluation is only one stage in the lifecycle
- strategy decision - executor acceptance or rejection must be first-class state
- execute command - venue submission and downstream outcome must be represented separately
- executor submission result - durable reason codes must drive operator labels
- downstream venue or relay outcome where available - forbidden labels that collapse multiple meanings, especially `Actionable`, must be removed
- later settled inventory deltas attributable to that quote
The turn passes only if the operator can distinguish submission from later outcome and can inspect a recent completed path with explicit settled attribution instead of implied completion. The turn passes only if an operator can inspect a quote and immediately understand whether it was filtered, rejected, blocked, submitted, failed, awaiting venue outcome, not filled, or completed, and why.
## Scope ## Scope
- [I017] Per-trade realized attribution: link each successful trade to actual settled inventory deltas and attributable costs so the system can report realized net contribution per trade instead of only expected edge. - [I021] Quote lifecycle truth and execution explanation: replace ambiguous dashboard verdicts with a per-quote state machine that shows exactly why a quote was filtered, rejected, blocked, submitted, not filled, or executed, with durable reason codes and operator-facing traceability.
- [I018] Quote-to-outcome and markout analytics: link quote, response, decision, execution result, and settlement, then store later reference-price markouts to measure adverse selection and quote quality. - Cover the live path from:
- Focus on the active NEAR Intents BTC/EURe venue and the repo-owned path already in production. - raw or normalized quote observation
- Cover recent rows first; historical backfill is secondary unless required to prove the live path. - strategy decision
- execute-trade command emission
- executor result
- solver relay or venue outcome where available
- Update the dashboard surfaces that currently expose quote or strategy truth:
- Strategy page
- any quote or recent-decision tables tied to the active pair
- quote-id presentation and operator trace affordances
## Assumptions ## Assumptions
- The venue or relay emits enough downstream identifiers or status surfaces to link at least some submitted quotes to later terminal outcomes. - The existing durable stores already contain enough information for at least the current live path through strategy decision and executor result.
- Inventory snapshots and durable history can support quote-to-settlement attribution for the active pair, even if the first version uses a narrow matching heuristic. - Some downstream venue-outcome states may still be partially fake or unavailable for older rows; if so, the UI must say that plainly rather than implying more certainty.
- Some rows will still remain unattributed or partially inferred; the UI and stored records must say that plainly. - The immediate turn should prioritize truthful lifecycle explanation over broader analytics such as markout or long-window outcome attribution.
- This turn should prioritize truthful linkage and settlement evidence over broad analytics polish. - The prevention strategy must be implemented in repo code and tests rather than left to reviewer judgment alone.
## Turn-shaping rules ## Turn-shaping rules
- `submitted` remains non-terminal evidence. - `Actionable` is forbidden as an operator-facing state or label.
- `completed`, `not filled`, `settled`, `realized`, and `asset delta` are forbidden unless backed by a durable linked record representing that fact. - Operator-facing labels must not overstate event certainty.
- If settlement attribution is heuristic rather than exact, the stored attribution record and operator surface must say so explicitly. - Terms such as `trade`, `success`, `filled`, `completed`, `profit`, and `asset delta` are forbidden unless backed by a durable event explicitly representing that fact.
- Do not build a broad analytics suite before the quote-to-outcome path is durably linked. - Do not add a second analytics product. Stay focused on per-quote lifecycle truth for the live active pair.
- Prefer one repo-owned outcome and attribution model reused by storage, dashboard, and later analytics. - Do not invent lifecycle states that cannot be backed by durable repo-owned evidence.
- If a state transition is inferred rather than durably observed, the UI must make that distinction explicit.
- Prefer a small, explicit state machine over a long list of loosely related badges.
## Non-goals ## Non-goals
- No new venue integration. - No new venue integrations.
- No generalized PnL accounting for all treasury cashflows. - No broad historical markout analytics turn.
- No broad historical backfill project unless needed to prove current-path linkage. - No new execution automation or risk widening.
- No strategy changes beyond what is required to preserve truthful lifecycle and attribution semantics. - No redesign of the entire dashboard visual system beyond what is needed to make the quote lifecycle understandable.
## Required operator behavior ## Required operator behavior
### Outcome truth ### Lifecycle truth
For a recent submitted quote, the dashboard must be able to render one of: For each visible quote or decision row, the operator must be able to identify the current lifecycle state from a bounded set such as:
- `Filtered`
- `Rejected by strategy`
- `Blocked before submit`
- `Submission failed`
- `Submitted` - `Submitted`
- `Awaiting outcome` - `Awaiting venue outcome`
- `Not filled` - `Not filled` or equivalent final non-fill state, if durable evidence exists
- `Completed` - `Completed` or equivalent successful terminal state, if durable evidence exists
The label must be driven by the strongest durable evidence currently stored. Exact labels may vary, but they must be specific and mutually meaningful.
### Settlement truth The repo must adopt a hard evidence-state vocabulary for this turn. At minimum:
For a recent completed quote, the operator must be able to inspect: - `observed`
- quote id - `evaluated`
- decision id - `command_emitted`
- command id - `rejected`
- executor result id or submission timestamp - `blocked`
- linked terminal outcome evidence - `submitted`
- linked settled asset delta or explicitly missing settled delta - `failed`
- `awaiting_outcome`
- `completed`
### Attribution truth No operator surface may collapse these into softer or stronger claims.
If the system reports realized contribution, it must be derived from:
- linked settled asset movement
- explicit attributable costs where available
If costs or full settlement are missing, the system must not claim net realized truth. ### Reason truth
Each non-terminal or terminal non-trade state must expose a clear decisive reason, such as:
- unsupported pair
- below edge threshold
- inventory unavailable
- executor disarmed
- executor paused
- submission failed
- venue timeout
- quote expired
### Markout truth If the decisive reason is not known, the surface must say that plainly instead of inventing confidence.
If markout is stored for completed or submitted rows, it must:
- be clearly labeled as later reference-price comparison
- remain separate from realized settlement attribution
## Semantic invariants ### Traceability
The implementation and tests must enforce at least: For each quote row the operator must be able to access:
- `submitted != completed` - quote id in a non-hidden, copyable form
- `completed` requires linked terminal outcome evidence - decision id where present
- settled asset delta requires linked settlement evidence, not quote terms - command id where present
- markout is not realized PnL - execution result where present
- unattributed inventory movement must not be silently assigned to a quote - pair and direction
The operator must be able to reason from a single row without manually cross-correlating multiple pages.
### UI language
The UI must not render `Actionable`.
Any replacement label must answer a concrete operator question, such as:
- did strategy approve this?
- was a command emitted?
- was the command blocked?
- was it submitted?
- did it fail?
### Semantic invariants
The implementation and tests must enforce at least these invariants:
- `submitted` is not `completed`
- `submitted` is not a realized asset delta
- executor-side blocking is not strategy rejection
- stronger labels must not be rendered from weaker evidence
These invariants are proof-critical, not optional cleanup.
## Definition of done ## Definition of done
- A durable quote outcome link exists from submission to later outcome where available. - `Actionable` is removed from operator-facing dashboard surfaces.
- The repo stores an explicit per-quote outcome or attribution record for the active path. - A durable quote lifecycle model exists in repo-owned code and is used by the dashboard.
- The dashboard can show at least one recent path as `Completed` only when durable linked evidence supports it. - At least the current live quote path through strategy decision and executor result is rendered coherently per quote.
- The dashboard can show non-fill or still-awaiting paths truthfully where that evidence exists. - The operator can tell, from one row, why a recent quote did or did not turn into a submitted trade.
- Recent settled asset delta or explicit lack of attribution is visible per completed row. - Quote ids are copyable and clearly visible enough for tracing.
- Submission-term tables and summaries do not overclaim settled truth. - overloaded backend and UI names that imply stronger certainty than the evidence supports are removed or renamed
- Regression tests cover the negative semantic boundaries above. - Regression tests cover at least:
- strategy-approved but executor-disarmed rows
- submitted rows
- forbidden ambiguous label removal
- forbidden semantic overclaims such as treating `submitted` as `completed`
For this turn to close with status `passed`, the specific operator question:
`Why did this quote not trade?`
must be answerable directly from the dashboard for recent rows without needing manual database inspection.
## Validation evidence required ## Validation evidence required
- direct evidence from deployed dashboard or bootstrap payload that recent rows separate `Submitted`, `Blocked`, `Rejected`, `Not filled`, and `Completed` when the evidence exists - direct UI or bootstrap evidence that recent rows show explicit lifecycle states instead of `Actionable`
- direct evidence that a completed row shows linked settled attribution rather than quote terms alone - direct evidence that a strategy-approved but executor-disarmed row renders as blocked or rejected with reason
- direct evidence that a submission-only row still does not claim completion or realized asset movement - direct evidence that a submitted row renders as submitted
- automated test evidence for quote-to-outcome linkage - direct evidence that quote ids are directly usable for tracing
- automated test evidence for settlement attribution boundaries - automated test evidence for lifecycle derivation and dashboard rendering
- automated test evidence for negative semantic invariants, especially `submitted != completed`
## Failure conditions ## Failure conditions
- the system still cannot represent downstream terminal outcome beyond submission - `Actionable` still appears in the dashboard
- any UI or backend surface claims completion from submission-only evidence - the operator still cannot distinguish strategy approval from execution submission
- settled asset delta is still derived from quoted terms rather than linked settlement evidence - non-trade rows still lack a decisive reason
- markout or later reference comparison is presented as realized PnL - quote ids remain hidden or non-copyable
- outcome attribution silently guesses across ambiguous rows without recording uncertainty - lifecycle labels are only cosmetic and not backed by durable repo-owned state
- the repo still uses `trade` or `asset delta` language for mere submission evidence
- tests still encode the old overclaiming semantics
## Current real before this turn ## Current real before this turn
- quote, decision, command, and execution submission result are durable - strategy decisions are stored durably
- the dashboard now renders those stages truthfully - execution results are stored durably
- submission counts and recent submission terms are constrained to submission evidence - command ids, decision ids, and quote ids already exist in the durable path
- the operator dashboard already serves recent decisions and execution-adjacent state
## Deliberately not built by this proof ## Deliberately not built by this proof
- full treasury fee ledger - full venue settlement attribution for all historic trades
- generalized tax or accounting treatment - generalized quote analytics beyond lifecycle explanation
- multi-venue settlement harmonization - multi-venue lifecycle harmonization
## Prevention requirements for this proof ## Prevention requirements for this proof
- For every new `Completed`, `Not filled`, or realized attribution label: - Add a truth-review checklist to the implementation work:
- what exact durable record backs it - what exact durable table or event backs this label?
- what linkage key or heuristic connects it to the quote - what is the strongest claim the evidence supports?
- what uncertainty remains - what would make this wording false?
- what regression test prevents future overclaiming - what negative regression test prevents that overclaim from returning?
- Separate lifecycle derivation from summary metrics so summaries are computed from lifecycle states rather than raw convenience queries.

View file

@ -1,306 +0,0 @@
# Implementation Turn: quote lifecycle truth and execution explanation
Status: open
Opened: 2026-04-09
## Goal
Replace ambiguous quote and decision wording with a truthful per-quote lifecycle that tells the operator exactly why a quote was filtered, rejected, blocked, submitted, failed, not filled, or completed.
## Selected backlog items
- [I021] Quote lifecycle truth and execution explanation: replace ambiguous dashboard verdicts with a per-quote state machine that shows exactly why a quote was filtered, rejected, blocked, submitted, not filled, or executed, with durable reason codes and operator-facing traceability.
## Design rules
- Treat quote lifecycle as product truth, not UI decoration.
- Strategy verdict is not the final operator answer.
- Prefer one explicit lifecycle derivation path shared by backend and dashboard over ad hoc page-specific wording.
- Do not invent downstream certainty where durable evidence is absent.
- Remove `Actionable` completely from operator-facing copy.
- Do not use stronger operator words than the durable evidence supports.
- Fix semantic bugs by changing both the code and the tests that encoded the wrong assumption.
## Problem statement for this turn
The current dashboard still forces operators to infer too much:
- `Actionable` does not say whether a command was emitted or submitted
- the Strategy page mixes strategy and execution truth
- executor-rejected rows are not clearly distinguishable from strategy-rejected rows
- quote ids are truncated and awkward to use during debugging
The repo already stores enough of the real lifecycle to do better:
- quote id
- decision id
- emitted command id
- execution result status and result code
The recent submission-versus-trade bug showed the broader prevention gap:
- wrong semantics were encoded in backend query names
- the dashboard rendered stronger claims than the evidence supported
- tests asserted the wrong meaning instead of protecting the truth
The turn therefore needs to improve:
- lifecycle derivation
- durable reason mapping
- recent-row rendering
- trace affordances
## Lifecycle model for this turn
Implement one repo-owned lifecycle derivation for recent rows, using durable evidence in this order:
1. Quote observed
2. Strategy evaluated
3. Command emitted or not emitted
4. Executor result observed or absent
5. Venue downstream outcome when available
The first mandatory states are:
- `Filtered`
- `Rejected`
- `Blocked`
- `Submitted`
- `Failed`
- `Awaiting outcome`
- `Completed`
These states must become the repo-owned evidence vocabulary for operator surfaces and summaries.
Suggested meanings:
- `Filtered`
quote never entered the active trade path or was excluded before strategy decision
- `Rejected`
strategy evaluated the quote and decided not to trade
- `Blocked`
strategy approved or emitted a command, but execution did not proceed due to control state or another repo-owned gate
- `Submitted`
executor accepted the command and successfully submitted a quote response
- `Failed`
execution submission failed technically
- `Awaiting outcome`
submitted to venue, but no later durable terminal venue outcome exists yet
- `Completed`
durable evidence shows the trade completed successfully
Do not show states we cannot support yet for a given row.
## Reason-code model
For each lifecycle state, map durable payload fields to a small operator reason taxonomy.
Examples:
- strategy reason codes:
- unsupported_pair
- below_edge_threshold
- inventory_unavailable
- stale_reference_price
- executor reason codes:
- executor_disarmed
- executor_paused
- submission_failed
- quote_response_ok
- downstream outcome reasons if available:
- expired
- not_filled
- completed
If the exact reason is missing:
- expose `reason_unknown`
- keep the row truthful instead of synthesizing an explanation
## Semantic guardrails for this turn
### 1. Ban overloaded certainty words unless evidence justifies them
Review and remove or rename operator-facing and backend terms such as:
- `successfulTradeCount`
- `lastSuccessfulTradeAt`
- `loadSuccessfulTradesPage`
- `trade_asset_changes`
- any UI label implying trade completion, realized asset movement, or PnL attribution from mere submission evidence
Allowed wording must be tied to the strongest durable evidence actually present.
### 2. Encode semantic invariants in code and tests
Add explicit checks and regression coverage for:
- `submitted != completed`
- `submitted != realized asset delta`
- executor blocking != strategy rejection
- no UI label may claim trade completion from submission-only evidence
Negative tests are required, not just positive-path tests.
## Backend changes
### 1. Add a lifecycle derivation helper
Create or extend a backend module that derives quote lifecycle from:
- recent trade decisions
- recent execution results
- later terminal records only where they are real
- any available quote-status or venue result surfaces
It should emit a normalized row object with:
- `quote_id`
- `decision_id`
- `command_id`
- `pair`
- `direction`
- `lifecycle_state`
- `lifecycle_label`
- `reason_code`
- `reason_text`
- timestamps for the latest known stage
- stage details for tooltips or drilldown
### 2. Join decision and execution truth explicitly
The backend should no longer leave the frontend to infer execution from isolated tables.
For each recent quote/decision row:
- attach the matching execution result by `command_id`, `decision_id`, or `quote_id`
- attach terminal completion or non-fill evidence only where it is genuinely available
- expose whether the row is strategy-only, strategy-plus-command, or strategy-plus-execution
As part of this phase, rename misleading backend aggregation helpers and payload fields where practical so code meaning matches evidence meaning.
### 3. Preserve operator drilldown identifiers
Ensure the bootstrap payload exposes:
- full quote id
- full decision id
- full command id
Avoid requiring the frontend to reconstruct or guess identifiers from formatted strings.
## Dashboard changes
### 4. Remove forbidden language
Remove `Actionable` from:
- Strategy page tables
- any lifecycle badge or verdict cell
- any supporting labels or legends
Replace it with explicit state labels driven by lifecycle derivation.
Also remove or rename any remaining wording that presents submission evidence as trade completion or realized asset movement.
### 5. Make recent rows self-explanatory
For each row, render:
- primary lifecycle state
- secondary reason text
- quote id with copy action
- command id if emitted
- timestamps
The operator should be able to scan rows and answer:
- why no trade happened
- whether the system tried to trade
- whether failure was strategic, operational, or downstream
### 6. Add trace affordances
At minimum:
- copy button for quote id
- avoid over-truncating ids without recovery path
- show linked ids in a dedicated trace column or expanded detail panel
If the row layout gets crowded, prefer an expandable detail tray over hiding identifiers.
## Page-level application
### Strategy page
This page should become the primary recent quote-decision-execution lifecycle surface.
It should show:
- the latest recent rows for the active pair
- lifecycle state rather than strategy-only verdict
- explicit explanation text
If a strategy-only summary remains, it must be visually separate from per-quote lifecycle truth.
### Related quote surfaces
Inspect quote and system surfaces for similar ambiguity and align the wording if they expose the same concepts.
Do not let one page say `Submitted` while another page still says `Actionable` for the same row.
Do not let one page say `trade` while another page only has `submitted` evidence for the same row.
## Data and state edge cases
- Strategy decision exists, no command emitted:
render as `Rejected` with strategy reason
- Command emitted, no execution result yet:
render as `Blocked` or `Awaiting executor` only if that distinction is durably supportable; otherwise use a truthful pending label
- Execution result `executor_disarmed`:
render as `Blocked` with reason `executor disarmed`
- Execution result `submission_failed`:
render as `Failed`
- Execution result `submitted`:
render as `Submitted` or `Awaiting outcome`
- Successful trade summary exists but no explicit per-quote completion event:
only promote to `Completed` where the durable linkage is real
- Submission evidence appears in profitability or summary widgets:
rename and constrain those widgets so they do not imply realized trade truth
## Concrete implementation order
### Phase 1. Define lifecycle derivation
- inspect current durable decision and execution payloads
- write the normalized lifecycle state mapping
- define forbidden and allowed operator labels
- list misleading backend and UI names that must be changed
- define the semantic invariant tests up front
### Phase 2. Implement backend aggregation
- derive unified recent lifecycle rows
- expose full identifiers and reason codes
- keep old consumers working until the frontend is switched
- rename misleading submission-as-trade helpers and summary fields where touched
### Phase 3. Update Strategy page rendering
- replace verdict column with lifecycle state
- add reason text
- add quote-id copy affordance
- surface command id and execution state where relevant
### Phase 4. Tighten wording and consistency
- remove `Actionable`
- align supporting labels
- ensure blocked vs rejected vs submitted are clearly distinct
- ensure submitted vs completed vs realized asset movement are clearly distinct
### Phase 5. Validate with live recent rows
- verify a row rejected due to executor disarmed renders as blocked with reason
- verify a submitted row renders as submitted
- verify quote ids can be copied and used for tracing
- verify no submission-only row is rendered as a trade, completion, or realized asset delta
## Test plan
- unit tests for lifecycle derivation from:
- strategy-rejected rows
- executor-disarmed rows
- submission-failed rows
- submitted rows
- unit tests for semantic invariants:
- submitted rows must not be counted as completed trades
- submission-only rows must not render as asset deltas
- dashboard bootstrap tests for:
- forbidden `Actionable` removal
- explicit lifecycle labels
- reason text rendering
- identifier exposure
- dashboard summary tests for renamed or narrowed submission metrics
- frontend component tests if needed for copy affordance or row rendering logic
No lifecycle ambiguity fix is complete without a regression test proving the old ambiguous wording or overclaim cannot return.
## Validation checklist against the proof
- `Actionable` no longer appears
- strategy approval is visibly distinct from execution submission
- recent blocked rows explain why they did not trade
- recent submitted rows show that they were submitted
- quote ids are directly usable from the dashboard
- submission-only evidence is no longer rendered as trade completion or asset delta truth
## Failure modes to plan for
- the backend joins rows incorrectly and attributes the wrong execution result
- the UI uses softer wording than the backend lifecycle state
- older rows lack enough evidence and the UI pretends certainty
- ids are still truncated without a copy or expand path
- misleading legacy names remain in place and create new semantic drift later
## Truth review checklist for this turn
For every operator-facing label, metric, table, or badge touched in this proof:
- what exact durable table or event backs it?
- what is the strongest claim the evidence supports?
- what wording would overclaim certainty?
- what negative regression test locks that boundary in?

View file

@ -1,200 +0,0 @@
# Implementation Proof: quote lifecycle truth and execution explanation
Status: open
Opened: 2026-04-09
## Target outcome
This turn proves that `unrip` can explain every quote outcome in operator-visible, durable terms instead of forcing the operator to infer meaning from ambiguous labels.
The concrete target is the live NEAR Intents BTC/EURe system:
- each quote row must expose its current lifecycle state
- each non-trade outcome must expose the decisive reason code
- execution submission must be distinguishable from strategy approval
- blocked, rejected, submitted, failed, and not-filled paths must be visibly different
- quote identifiers must be directly usable by operators for tracing and support
- operator-facing labels must not overclaim beyond the durable evidence actually stored
## Why this is a meaningful architecture test
The current operator surface still fails a core thesis requirement:
- the Strategy page shows `Actionable`, which does not tell the operator whether a trade was actually submitted
- an operator looking at one quote cannot answer, at a glance, why it did or did not become a trade
- quote ids are hidden behind truncation with no direct copy affordance
- execution truth exists durably in PostgreSQL, but the UI does not surface the lifecycle coherently
That is not just a copy problem. It is an observability gap in the trading product itself. If the system cannot explain a quote outcome precisely, execution is outrunning observability.
The immediate trigger for this turn is a real semantic failure:
- the dashboard treated `trade_execution_results.status = submitted` as a successful trade
- recent submitted quote terms were rendered as if they were realized asset deltas
- tests passed because that wrong assumption had been encoded into the test suite itself
This turn must therefore fix both the UI and the conditions that allowed the mistake through.
## Hypothesis
`unrip` becomes more trustworthy if quote handling is modeled and rendered as an explicit lifecycle instead of a single strategy verdict:
- strategy evaluation is only one stage in the lifecycle
- executor acceptance or rejection must be first-class state
- venue submission and downstream outcome must be represented separately
- durable reason codes must drive operator labels
- forbidden labels that collapse multiple meanings, especially `Actionable`, must be removed
The turn passes only if an operator can inspect a quote and immediately understand whether it was filtered, rejected, blocked, submitted, failed, awaiting venue outcome, not filled, or completed, and why.
## Scope
- [I021] Quote lifecycle truth and execution explanation: replace ambiguous dashboard verdicts with a per-quote state machine that shows exactly why a quote was filtered, rejected, blocked, submitted, not filled, or executed, with durable reason codes and operator-facing traceability.
- Cover the live path from:
- raw or normalized quote observation
- strategy decision
- execute-trade command emission
- executor result
- solver relay or venue outcome where available
- Update the dashboard surfaces that currently expose quote or strategy truth:
- Strategy page
- any quote or recent-decision tables tied to the active pair
- quote-id presentation and operator trace affordances
## Assumptions
- The existing durable stores already contain enough information for at least the current live path through strategy decision and executor result.
- Some downstream venue-outcome states may still be partially fake or unavailable for older rows; if so, the UI must say that plainly rather than implying more certainty.
- The immediate turn should prioritize truthful lifecycle explanation over broader analytics such as markout or long-window outcome attribution.
- The prevention strategy must be implemented in repo code and tests rather than left to reviewer judgment alone.
## Turn-shaping rules
- `Actionable` is forbidden as an operator-facing state or label.
- Operator-facing labels must not overstate event certainty.
- Terms such as `trade`, `success`, `filled`, `completed`, `profit`, and `asset delta` are forbidden unless backed by a durable event explicitly representing that fact.
- Do not add a second analytics product. Stay focused on per-quote lifecycle truth for the live active pair.
- Do not invent lifecycle states that cannot be backed by durable repo-owned evidence.
- If a state transition is inferred rather than durably observed, the UI must make that distinction explicit.
- Prefer a small, explicit state machine over a long list of loosely related badges.
## Non-goals
- No new venue integrations.
- No broad historical markout analytics turn.
- No new execution automation or risk widening.
- No redesign of the entire dashboard visual system beyond what is needed to make the quote lifecycle understandable.
## Required operator behavior
### Lifecycle truth
For each visible quote or decision row, the operator must be able to identify the current lifecycle state from a bounded set such as:
- `Filtered`
- `Rejected by strategy`
- `Blocked before submit`
- `Submission failed`
- `Submitted`
- `Awaiting venue outcome`
- `Not filled` or equivalent final non-fill state, if durable evidence exists
- `Completed` or equivalent successful terminal state, if durable evidence exists
Exact labels may vary, but they must be specific and mutually meaningful.
The repo must adopt a hard evidence-state vocabulary for this turn. At minimum:
- `observed`
- `evaluated`
- `command_emitted`
- `rejected`
- `blocked`
- `submitted`
- `failed`
- `awaiting_outcome`
- `completed`
No operator surface may collapse these into softer or stronger claims.
### Reason truth
Each non-terminal or terminal non-trade state must expose a clear decisive reason, such as:
- unsupported pair
- below edge threshold
- inventory unavailable
- executor disarmed
- executor paused
- submission failed
- venue timeout
- quote expired
If the decisive reason is not known, the surface must say that plainly instead of inventing confidence.
### Traceability
For each quote row the operator must be able to access:
- quote id in a non-hidden, copyable form
- decision id where present
- command id where present
- execution result where present
- pair and direction
The operator must be able to reason from a single row without manually cross-correlating multiple pages.
### UI language
The UI must not render `Actionable`.
Any replacement label must answer a concrete operator question, such as:
- did strategy approve this?
- was a command emitted?
- was the command blocked?
- was it submitted?
- did it fail?
### Semantic invariants
The implementation and tests must enforce at least these invariants:
- `submitted` is not `completed`
- `submitted` is not a realized asset delta
- executor-side blocking is not strategy rejection
- stronger labels must not be rendered from weaker evidence
These invariants are proof-critical, not optional cleanup.
## Definition of done
- `Actionable` is removed from operator-facing dashboard surfaces.
- A durable quote lifecycle model exists in repo-owned code and is used by the dashboard.
- At least the current live quote path through strategy decision and executor result is rendered coherently per quote.
- The operator can tell, from one row, why a recent quote did or did not turn into a submitted trade.
- Quote ids are copyable and clearly visible enough for tracing.
- overloaded backend and UI names that imply stronger certainty than the evidence supports are removed or renamed
- Regression tests cover at least:
- strategy-approved but executor-disarmed rows
- submitted rows
- forbidden ambiguous label removal
- forbidden semantic overclaims such as treating `submitted` as `completed`
For this turn to close with status `passed`, the specific operator question:
`Why did this quote not trade?`
must be answerable directly from the dashboard for recent rows without needing manual database inspection.
## Validation evidence required
- direct UI or bootstrap evidence that recent rows show explicit lifecycle states instead of `Actionable`
- direct evidence that a strategy-approved but executor-disarmed row renders as blocked or rejected with reason
- direct evidence that a submitted row renders as submitted
- direct evidence that quote ids are directly usable for tracing
- automated test evidence for lifecycle derivation and dashboard rendering
- automated test evidence for negative semantic invariants, especially `submitted != completed`
## Failure conditions
- `Actionable` still appears in the dashboard
- the operator still cannot distinguish strategy approval from execution submission
- non-trade rows still lack a decisive reason
- quote ids remain hidden or non-copyable
- lifecycle labels are only cosmetic and not backed by durable repo-owned state
- the repo still uses `trade` or `asset delta` language for mere submission evidence
- tests still encode the old overclaiming semantics
## Current real before this turn
- strategy decisions are stored durably
- execution results are stored durably
- command ids, decision ids, and quote ids already exist in the durable path
- the operator dashboard already serves recent decisions and execution-adjacent state
## Deliberately not built by this proof
- full venue settlement attribution for all historic trades
- generalized quote analytics beyond lifecycle explanation
- multi-venue lifecycle harmonization
## Prevention requirements for this proof
- Add a truth-review checklist to the implementation work:
- what exact durable table or event backs this label?
- what is the strongest claim the evidence supports?
- what would make this wording false?
- what negative regression test prevents that overclaim from returning?
- Separate lifecycle derivation from summary metrics so summaries are computed from lifecycle states rather than raw convenience queries.