# Implementation Turn: settlement-aware strategy and inventory-skew controls Status: open Opened: 2026-04-10 ## Goal Use quote outcome truth, live inventory, and benchmark hold comparisons to make strategy thresholds and side selection explicit so the system trades only when evidence says the execution opportunity is worth changing inventory. ## Selected backlog items - [I015] 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 ## Design rules - Keep the approved base threshold at `1.49%`. - Keep notional limits unchanged unless separately approved. - Treat inventory policy as strategy evidence, not as profitability truth. - Keep submitted, not-filled, and completed outcome counts semantically separate. - Store enough fields on each decision to replay why the strategy approved or rejected a quote. ## Problem statement The current system can now say whether submitted quotes became linked asset movement, inferred not-fills, or are still submitted-only. The strategy still mostly answers a simpler question: does raw reference edge clear the threshold and is source inventory available? That is not enough for a real operator workflow. A quote that clears raw edge may still sell down scarce inventory, worsen the BTC/EURe mix, or repeat a side with poor recent outcome evidence. Conversely, a quote with the same raw edge may be more desirable if it moves inventory toward target. This turn should make that policy explicit and visible. ## Backend changes ### 1. Define strategy inventory policy - Add repo-owned config for target BTC value share and tolerance band. - Use current spendable BTC/EURe inventory plus latest reference price to compute current value mix. - For a candidate quote, compute projected post-trade mix using the proposed maker-side asset deltas. - Classify direction as `improves_inventory`, `within_band`, or `worsens_inventory`. - Keep policy disabled or neutral if required inputs are missing, with a visible reason. ### 2. Compute effective threshold - Keep `base_threshold_pct = 1.49`. - Add an explicit `effective_threshold_pct` to each decision. - If inventory direction worsens target skew, require extra edge or reject with `inventory_skew_worsens`. - If inventory direction improves target skew, do not lower below the approved base threshold unless the user separately approves it. - Store the adjustment components separately from the final threshold. ### 3. Add outcome-confidence inputs - Aggregate recent quote outcomes by side over a small explicit window. - Count submitted, not-filled, completed-heuristic, and completed-linked separately. - Do not count submitted as completion. - If outcome confidence affects threshold or reason, store the exact counts and window on the decision. ### 4. Extend durable decision payloads Each strategy decision should include: - `base_threshold_pct` - `effective_threshold_pct` - `threshold_adjustments` - `inventory_policy` - `inventory_skew_before` - `inventory_skew_after` - `inventory_direction` - `outcome_confidence` - `decision_reason` ### 5. Dashboard aggregation - Show base threshold and effective threshold on recent strategy/lifecycle rows. - Show inventory direction and decisive policy reason. - Keep quote ids copyable and full lifecycle reason visible. - Add a compact strategy policy panel with current target mix, current mix, and recent outcome counts. ## UI changes ### Strategy page - Add columns or row details for: - raw edge - base threshold - effective threshold - inventory direction - decisive reason - Keep successful-trade and lifecycle sections truthful from the previous turn. ### Funds page - Keep `Portfolio vs simple hold` separate from realized PnL. - If inventory target mix is shown on Funds, label it as policy context, not profit. ### System page - Surface strategy policy config and freshness only if it is directly useful for operator validation. ## Edge cases - Missing price: reject or defer with `reference_price_unavailable`. - Missing inventory: reject or defer with `inventory_unavailable`. - Candidate quote has unsupported assets: reject with `unsupported_pair`. - Source inventory is insufficient: keep `insufficient_inventory`, not `inventory_skew_worsens`. - Quote improves skew but does not clear base threshold: reject with a reason that says raw edge failed base threshold. - Recent outcomes are all submitted-only: outcome confidence is unknown, not good. - Recent movement is heuristic: count separately from linked terminal settlement. ## Concrete implementation order ### Phase 1. Model and tests - Add pure helper functions for inventory value mix, projected post-trade mix, direction classification, and effective threshold. - Add tests for improving, neutral, and worsening inventory directions. - Add tests that threshold never drops below `1.49`. ### Phase 2. Strategy integration - Wire helpers into `src/core/strategy.mjs` and `src/apps/strategy-engine.mjs`. - Extend emitted decision payloads with policy fields. - Preserve existing execution command shape unless size-limiting is implemented. ### Phase 3. Outcome-confidence integration - Load or derive recent outcome counts from existing quote outcome records where the strategy process can access them. - If direct DB access from strategy is too invasive, expose counts only on the dashboard in this turn and record that strategy-side outcome adjustment remains fake. - Add regression tests for submitted-only counts. ### Phase 4. Operator surfaces - Update dashboard bootstrap and Strategy page to render the new policy fields. - Ensure no operator-facing `Actionable` label returns. - Ensure no submitted-only row is described as completed or successful. ### Phase 5. Deploy and validate - Run targeted tests plus full `npm test`. - Build the dashboard bundle. - Commit with required proof body. - Push to `forgejo/main`. - Validate rollout image, strategy state, executor state, dashboard bootstrap, and at least one recent decision carrying inventory-policy fields. ## Test plan - Unit tests for inventory-skew direction. - Unit tests for effective threshold calculation. - Unit tests for missing inputs and insufficient inventory reason precedence. - Dashboard tests for base/effective threshold rendering. - Negative tests: - submitted-only outcome count does not improve fill confidence - inventory-skew comparison is not labeled realized PnL - threshold below `1.49` is rejected or clamped unless explicitly configured in a test-only override ## Validation checklist against the proof - Live strategy `/state` shows decisions with inventory-policy fields. - Dashboard Strategy page can explain a quote that passed raw edge but was withheld or size-limited by inventory policy. - Dashboard Strategy page can explain a quote that improves inventory and clears base threshold. - Executor remains armed if it was armed before deployment. - The repo still deploys fully from push without manual cluster reconciliation. ## Known fakes allowed at start of this turn - Realized net PnL remains unavailable without fee/cost attribution. - Venue-native terminal fill events remain unavailable. - Outcome-confidence may be dashboard-only if strategy DB access is not justified in the implementation.