Compare commits

..

2 commits

Author SHA1 Message Date
philipp
208be20a1c Plan turn: execution outcome truth and settled attribution
All checks were successful
deploy / deploy (push) Successful in 31s
Proof: Open the next implementation turn focused on durable downstream outcome linkage and settled inventory attribution for executed quotes.
Assumptions: I017 and I018 belong to one coherent proof topic for the active NEAR Intents BTC/EURe path.
Still fake: Planning defines the next truth gap and validation target, but no downstream outcome or settlement attribution implementation exists yet.
2026-04-09 18:09:05 +02:00
philipp
bd72e355b1 Archive implementation turn: quote lifecycle truth and execution explanation
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.
2026-04-09 18:07:40 +02:00
6 changed files with 734 additions and 422 deletions

View file

@ -12,6 +12,7 @@ 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-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-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
## Planning Events
@ -25,3 +26,4 @@ Legacy note:
- 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 `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,8 +22,6 @@ 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
- [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
- [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.

View file

@ -1,306 +1,174 @@
# Implementation Turn: quote lifecycle truth and execution explanation
# Implementation Turn: execution outcome truth and settled attribution
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.
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.
## 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.
- [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.
- [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
- 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.
- Treat downstream outcome and settlement truth as part of the same shared evidence path, not separate dashboard decoration.
- Preserve the current turns semantic boundary: submission is still non-terminal.
- Store explicit linkage and attribution records instead of recomputing ad hoc joins differently across pages.
- If a linkage is heuristic, store the heuristic and expose uncertainty.
- Keep the first implementation narrow to the active pair and current venue.
## 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 repository now explains why a quote was rejected, blocked, or submitted, but it still does not fully explain what happened after submission:
- terminal outcome truth is absent or disconnected
- recent submission tables are still quote-term oriented rather than settlement oriented
- completed and realized labels cannot yet be proven from repo-owned durable records
- later analytics such as markout and realized contribution have no canonical per-quote linkage record
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
This turn must therefore improve:
- downstream outcome ingestion or linkage
- quote-to-outcome storage
- settlement attribution storage
- operator rendering of completed versus submission-only rows
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:
## Required evidence model
Add one repo-owned quote outcome and attribution model with at least:
- `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
- `execution_result_status`
- `outcome_status`
- `outcome_observed_at`
- `outcome_source`
- `attribution_status`
- `attributed_inventory_delta`
- `attribution_method`
- `markout_reference_price` where implemented
### 2. Join decision and execution truth explicitly
The backend should no longer leave the frontend to infer execution from isolated tables.
Suggested vocabulary:
- outcome states:
- `submitted`
- `awaiting_outcome`
- `not_filled`
- `completed`
- attribution states:
- `unattributed`
- `heuristic_match`
- `linked_settlement`
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
## Backend changes
As part of this phase, rename misleading backend aggregation helpers and payload fields where practical so code meaning matches evidence meaning.
### 1. Add durable outcome linkage
- inspect available downstream event sources, solver relay data, inventory movement evidence, and existing history tables
- add a durable record or derived snapshot that links a submitted quote to later terminal outcome when possible
- preserve source timestamps and raw evidence pointers
### 3. Preserve operator drilldown identifiers
Ensure the bootstrap payload exposes:
- full quote id
- full decision id
- full command id
### 2. Add durable settlement attribution
- link completed quote outcomes to later inventory movement for the active assets
- store both raw units and formatted operator values
- track whether the attribution is exact or heuristic
- do not report net realized contribution unless costs are explicitly present
Avoid requiring the frontend to reconstruct or guess identifiers from formatted strings.
### 3. Extend dashboard bootstrap models
- expose recent quote outcome rows with terminal evidence where available
- expose settled attribution separately from submitted quote terms
- ensure summary metrics count completed outcomes and submission-only rows separately
## Dashboard changes
### 4. Prepare markout support on the same linkage path
- if implemented in this turn, compute later reference-price markout from the linked quote or completion timestamp
- store it in a way that cannot be confused with realized settlement contribution
### 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
## UI changes
### Strategy page
This page should become the primary recent quote-decision-execution lifecycle surface.
- extend lifecycle rows so submitted paths can become `Awaiting outcome`, `Not filled`, or `Completed`
- show linked outcome reason and settlement attribution state
- keep quote, decision, and command trace ids visible
It should show:
- the latest recent rows for the active pair
- lifecycle state rather than strategy-only verdict
- explicit explanation text
### Funds page
- separate:
- recent submission terms
- recent settled attribution
- completed outcome ledger
- if no settled attribution exists yet for a completed row, say that plainly
If a strategy-only summary remains, it must be visually separate from per-quote lifecycle truth.
### Summary language
- introduce distinct labels for:
- recent submissions
- recent completed outcomes
- recent settled attributions
- never reuse one metric for all three concepts
### 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`:
## Edge cases
- submitted row with no later evidence:
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
- explicit expiry or non-fill evidence:
render as `Not filled`
- completed outcome with no attributable inventory delta yet:
render completion truthfully, but mark attribution as missing
- 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
### 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 1. Discover and define outcome sources
- inspect current relay, executor, and inventory evidence
- document what fields can carry downstream outcome and settlement linkage
- define exact versus heuristic attribution rules
### 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 2. Implement durable outcome and attribution records
- add storage or derived records for linked outcomes
- add storage or derived records for settlement attribution
- preserve raw references and timestamps
### 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 3. Update dashboard aggregation
- join recent lifecycle rows to outcome and attribution records
- split summary metrics and ledgers by evidence strength
- keep submission-only rows clearly non-terminal
### 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
### Phase 4. Validate on live data
- prove at least one recent row remains submission-only
- prove blocked and rejected rows remain distinct
- prove a completed or non-fill row appears only with durable linked evidence
- prove settled attribution is shown only when actual linked movement exists
## 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
- unit tests for outcome linkage:
- submitted with no outcome
- submitted with non-fill outcome
- submitted with completed outcome
- unit tests for attribution:
- completed with linked settlement
- completed without settlement yet
- ambiguous movement remains unattributed
- 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:
- 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.
- separated summary metrics
- completed rows carrying explicit outcome evidence
- unattributed rows staying plainly unattributed
## 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
- recent rows separate submitted, awaiting, not-filled, and completed where evidence exists
- completed rows show explicit outcome linkage
- settled attribution is visible and clearly sourced
- submission-only rows still do not claim completion or realized movement
- remaining uncertainty is named plainly
## 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
- linking the wrong inventory movement to a quote
- mistaking inventory rebalance or treasury movement for trade settlement
- rendering completed from incomplete venue evidence
- blending markout and realized attribution into one metric
- introducing hidden heuristics without storing them
## 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?
For every outcome or attribution field:
- what exact durable event or snapshot backs it
- how is the quote linked to it
- is the linkage exact or heuristic
- what wording would overclaim certainty
- what regression test prevents that overclaim from returning

254
PROOF.md
View file

@ -1,200 +1,138 @@
# Implementation Proof: quote lifecycle truth and execution explanation
# Implementation Proof: execution outcome truth and settled attribution
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.
This turn proves that `unrip` can move recent quote rows past submission-only evidence and into durable downstream outcome truth.
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
For the live NEAR Intents BTC/EURe system, the operator must be able to answer:
- was the quote merely submitted
- did the venue later complete or not fill it
- what settled inventory delta, if any, was actually observed afterward
- what part of the post-trade change is still inferred versus durably linked
## 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
The previous turn fixed an overclaiming dashboard, but it also exposed the next hard truth gap:
- `submitted` is now shown truthfully as non-terminal evidence
- downstream completion and non-fill states are still mostly absent from durable repo-owned data
- recent asset-term tables still describe submitted quote terms, not settled inventory truth
- realized attribution is still fake because quote response success is not the same thing as completed asset movement
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.
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.
## 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
`unrip` becomes materially more trustworthy if it durably links:
- quote
- strategy decision
- execute command
- executor submission result
- downstream venue or relay outcome where available
- later settled inventory deltas attributable to that quote
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.
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.
## 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
- [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.
- [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.
- Focus on the active NEAR Intents BTC/EURe venue and the repo-owned path already in production.
- Cover recent rows first; historical backfill is secondary unless required to prove the live path.
## 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.
- The venue or relay emits enough downstream identifiers or status surfaces to link at least some submitted quotes to later terminal outcomes.
- 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 rows will still remain unattributed or partially inferred; the UI and stored records must say that plainly.
- This turn should prioritize truthful linkage and settlement evidence over broad analytics polish.
## 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.
- `submitted` remains non-terminal evidence.
- `completed`, `not filled`, `settled`, `realized`, and `asset delta` are forbidden unless backed by a durable linked record representing that fact.
- If settlement attribution is heuristic rather than exact, the stored attribution record and operator surface must say so explicitly.
- Do not build a broad analytics suite before the quote-to-outcome path is durably linked.
- Prefer one repo-owned outcome and attribution model reused by storage, dashboard, and later analytics.
## 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.
- No new venue integration.
- No generalized PnL accounting for all treasury cashflows.
- No broad historical backfill project unless needed to prove current-path linkage.
- No strategy changes beyond what is required to preserve truthful lifecycle and attribution semantics.
## 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`
### Outcome truth
For a recent submitted quote, the dashboard must be able to render one of:
- `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
- `Awaiting outcome`
- `Not filled`
- `Completed`
Exact labels may vary, but they must be specific and mutually meaningful.
The label must be driven by the strongest durable evidence currently stored.
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`
### Settlement truth
For a recent completed quote, the operator must be able to inspect:
- quote id
- decision id
- command id
- executor result id or submission timestamp
- linked terminal outcome evidence
- linked settled asset delta or explicitly missing settled delta
No operator surface may collapse these into softer or stronger claims.
### Attribution truth
If the system reports realized contribution, it must be derived from:
- linked settled asset movement
- explicit attributable costs where available
### 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 costs or full settlement are missing, the system must not claim net realized truth.
If the decisive reason is not known, the surface must say that plainly instead of inventing confidence.
### Markout truth
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
### 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.
## Semantic invariants
The implementation and tests must enforce at least:
- `submitted != completed`
- `completed` requires linked terminal outcome evidence
- settled asset delta requires linked settlement evidence, not quote terms
- markout is not realized PnL
- unattributed inventory movement must not be silently assigned to a quote
## 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.
- A durable quote outcome link exists from submission to later outcome where available.
- The repo stores an explicit per-quote outcome or attribution record for the active path.
- The dashboard can show at least one recent path as `Completed` only when durable linked evidence supports it.
- The dashboard can show non-fill or still-awaiting paths truthfully where that evidence exists.
- Recent settled asset delta or explicit lack of attribution is visible per completed row.
- Submission-term tables and summaries do not overclaim settled truth.
- Regression tests cover the negative semantic boundaries above.
## 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`
- direct evidence from deployed dashboard or bootstrap payload that recent rows separate `Submitted`, `Blocked`, `Rejected`, `Not filled`, and `Completed` when the evidence exists
- direct evidence that a completed row shows linked settled attribution rather than quote terms alone
- direct evidence that a submission-only row still does not claim completion or realized asset movement
- automated test evidence for quote-to-outcome linkage
- automated test evidence for settlement attribution boundaries
## 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
- the system still cannot represent downstream terminal outcome beyond submission
- any UI or backend surface claims completion from submission-only evidence
- settled asset delta is still derived from quoted terms rather than linked settlement evidence
- markout or later reference comparison is presented as realized PnL
- outcome attribution silently guesses across ambiguous rows without recording uncertainty
## 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
- quote, decision, command, and execution submission result are durable
- the dashboard now renders those stages truthfully
- submission counts and recent submission terms are constrained to submission evidence
## Deliberately not built by this proof
- full venue settlement attribution for all historic trades
- generalized quote analytics beyond lifecycle explanation
- multi-venue lifecycle harmonization
- full treasury fee ledger
- generalized tax or accounting treatment
- multi-venue settlement 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.
- For every new `Completed`, `Not filled`, or realized attribution label:
- what exact durable record backs it
- what linkage key or heuristic connects it to the quote
- what uncertainty remains
- what regression test prevents future overclaiming

View file

@ -0,0 +1,306 @@
# 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

@ -0,0 +1,200 @@
# 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.