Compare commits

..

No commits in common. "55ece8f5f0bc97a0a0e102bb94e4a1215853e558" and "d5a7325e484f721cfc49165424517111b61c0374" have entirely different histories.

5 changed files with 192 additions and 483 deletions

View file

@ -14,7 +14,6 @@ Legacy note:
- 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. - 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.
- 2026-04-10: `execution-outcome-truth-and-settled-attribution` closed with status `passed`. Deployed e0dfd24, validated 1 completed heuristic settlement-attributed trade, 6 inferred not-filled outcomes, submitted-only rows without asset deltas, and stable armed strategy/executor at the approved 1.49% threshold. - 2026-04-10: `execution-outcome-truth-and-settled-attribution` closed with status `passed`. Deployed e0dfd24, validated 1 completed heuristic settlement-attributed trade, 6 inferred not-filled outcomes, submitted-only rows without asset deltas, and stable armed strategy/executor at the approved 1.49% threshold.
- 2026-04-12: `settlement-aware-strategy-and-inventory-skew-controls` closed with status `paused`. Paused after deploying approved 0.49 percent threshold, validating live quote intake recovery, and fixing NEAR Intents ingest reconnect-on-error; 0.49 percent submission resolved not_filled and full inventory-skew controls remain incomplete.
## Research Turns ## Research Turns
## Planning Events ## Planning Events
@ -30,4 +29,3 @@ Legacy note:
- 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. - 2026-04-09: opened implementation turn `execution-outcome-truth-and-settled-attribution` from backlog items I017, I018.
- 2026-04-10: opened implementation turn `settlement-aware-strategy-and-inventory-skew-controls` from backlog items I015. - 2026-04-10: opened implementation turn `settlement-aware-strategy-and-inventory-skew-controls` from backlog items I015.
- 2026-04-12: opened implementation turn `near-intents-request-creation-and-eure-to-btc-taker-flow` from backlog items I017.

View file

@ -1,156 +1,142 @@
# Implementation Turn: NEAR Intents request creation and EURe-to-BTC taker flow # Implementation Turn: settlement-aware strategy and inventory-skew controls
Status: open Status: open
Opened: 2026-04-12 Opened: 2026-04-10
## Goal ## Goal
Build a repo-owned path to create our own NEAR Intents EURe-to-BTC swap request from credited internal inventory, submit it only behind explicit gates, and show truthful request-to-settlement evidence in the dashboard. 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 ## Selected backlog items
- [I017] Repo-owned NEAR Intents request creation and EURe-to-BTC taker flow: create, sign, submit, and settle our own swap requests from credited inventory with truthful dashboard evidence. tags=intents,taker,execution,inventory,settlement - [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 ## Design rules
- Treat request creation as a new taker lifecycle, not as an incoming quote-response decision. - Keep the approved base threshold at `1.49%`.
- Preflight must be safe and side-effect-free. - Keep notional limits unchanged unless separately approved.
- Live submission must be explicit, idempotent, and durably recorded before the relay call. - Treat inventory policy as strategy evidence, not as profitability truth.
- Use only spendable credited EURe. - Keep submitted, not-filled, and completed outcome counts semantically separate.
- Keep all ids copyable: request id, idempotency key, intent hash or relay request id, submission id. - Store enough fields on each decision to replay why the strategy approved or rejected a quote.
- Submitted or relay-accepted does not mean completed.
- Completed requires inventory delta attribution.
## Problem statement ## Problem statement
The current system watches the NEAR Intents market and responds to other users' quotes. That is not enough to intentionally convert our EURe inventory to BTC. The operator wants a repo-owned way to create our own request on the intents market and eventually move EURe into BTC, with the same truth standard as the incoming quote lifecycle. 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?
The existing code can sign verifier token_diff payloads for quote responses and can submit quote_response over the solver relay websocket. It does not yet know how to publish a taker request, quote request, or swap intent that asks the market to fill our EURe-to-BTC order. 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 ## Backend changes
### 1. Verify request protocol ### 1. Define strategy inventory policy
- Identify the supported NEAR Intents method for creating our own request using primary code/docs or live non-mutating behavior. - Add repo-owned config for target BTC value share and tolerance band.
- Determine whether the method uses the existing solver relay websocket, a JSON-RPC HTTP endpoint, or a verifier contract call. - Use current spendable BTC/EURe inventory plus latest reference price to compute current value mix.
- Determine exact payload fields for EURe-to-BTC exact-in requests. - For a candidate quote, compute projected post-trade mix using the proposed maker-side asset deltas.
- Verify signed intent semantics: outgoing EURe, incoming BTC, deadline, nonce, verifier contract, signer. - Classify direction as `improves_inventory`, `within_band`, or `worsens_inventory`.
- Record a hard blocker if the protocol cannot be verified. - Keep policy disabled or neutral if required inputs are missing, with a visible reason.
### 2. Add request model and schemas ### 2. Compute effective threshold
- Add a canonical repo-owned request lifecycle model. - Keep `base_threshold_pct = 1.49`.
- Add event schemas for at least intent_request_preflight, intent_request_submit_command, intent_request_submission_result, and intent_request_outcome. - Add an explicit `effective_threshold_pct` to each decision.
- Persist request id, idempotency key, source/destination assets, requested spend, min receive, reference price, slippage, signer account, verifier contract, deadline, nonce, and created/submitted timestamps. - If inventory direction worsens target skew, require extra edge or reject with `inventory_skew_worsens`.
- Keep this model separate from incoming swap_demand, trade_decision, execute_trade, and trade_result events. - 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. Build preflight service logic ### 3. Add outcome-confidence inputs
- Load latest spendable EURe inventory from current inventory state or durable snapshot. - Aggregate recent quote outcomes by side over a small explicit window.
- Compute request amount from all spendable EURe minus an explicit reserve if configured, while allowing a smaller operator-specified amount for testing. - Count submitted, not-filled, completed-heuristic, and completed-linked separately.
- Compute expected BTC from reference price. - Do not count submitted as completion.
- Compute minimum BTC receive from explicit slippage basis points. - If outcome confidence affects threshold or reason, store the exact counts and window on the decision.
- Reject if reference price is stale, inventory is stale, amount is zero, amount exceeds spendable EURe, or signer is not registered.
- Return a draft request object without signing or submitting.
### 4. Build signing/envelope helpers ### 4. Extend durable decision payloads
- Add a helper for taker request signing/envelope construction once the verified protocol is known. Each strategy decision should include:
- Reuse buildIntentNonce only if nonce semantics match the request protocol. - `base_threshold_pct`
- Add deterministic signer tests for the exact signed payload. - `effective_threshold_pct`
- Keep quote-response signing tests unchanged. - `threshold_adjustments`
- `inventory_policy`
- `inventory_skew_before`
- `inventory_skew_after`
- `inventory_direction`
- `outcome_confidence`
- `decision_reason`
### 5. Build gated submit path ### 5. Dashboard aggregation
- Add a narrow request-executor or extend trade-executor only if responsibilities stay clear. - Show base threshold and effective threshold on recent strategy/lifecycle rows.
- Require explicit submit command with preflight id or idempotency key. - Show inventory direction and decisive policy reason.
- Mark request as submit_requested before the relay/API call. - Keep quote ids copyable and full lifecycle reason visible.
- Submit with timeout and reconnect-safe client behavior. - Add a compact strategy policy panel with current target mix, current mix, and recent outcome counts.
- Persist result as submitted, accepted_by_relay, failed, or protocol-specific status.
- Enforce idempotency so duplicate commands cannot submit twice.
### 6. Settlement attribution ## UI changes
- Extend outcome attribution to handle repo-created requests.
- Match settlement from inventory deltas: EURe decrease and BTC increase consistent with submitted request terms.
- Mark unresolved as awaiting_settlement before deadline/grace expires.
- Mark not_filled only after deadline/grace and fresh inventory evidence.
- Mark completed only with durable inventory movement evidence.
### 7. Dashboard and controls ### Strategy page
- Add a Funds or Strategy panel for Create BTC request with preflight amount, slippage/minimum BTC receive, dry-run/preflight action, and live submit only after a valid preflight. - Add columns or row details for:
- Add a repo-created requests table with request id, created/submitted time, source spend, min receive, state, decisive reason, relay/API response, settlement result, and expandable lifecycle. - raw edge
- Make request ids and returned intent/relay ids copyable. - base threshold
- Label live fund movement clearly; no green success label without settlement. - effective threshold
- inventory direction
- decisive reason
- Keep successful-trade and lifecycle sections truthful from the previous turn.
## Data and persistence ### Funds page
- Prefer adding narrow tables or durable event routes for request preflight, submit commands, submission results, and outcomes. - Keep `Portfolio vs simple hold` separate from realized PnL.
- Preserve raw relay/API responses alongside normalized lifecycle state. - If inventory target mix is shown on Funds, label it as policy context, not profit.
- Include enough fields to replay the request and reason about slippage, deadline, and settlement.
- Do not reuse incoming quote ids as request ids. ### System page
- Surface strategy policy config and freshness only if it is directly useful for operator validation.
## Edge cases ## Edge cases
- Missing request API evidence: stop with blocker. - Missing price: reject or defer with `reference_price_unavailable`.
- Signer not registered: block before signing/submission. - Missing inventory: reject or defer with `inventory_unavailable`.
- EURe inventory stale or unavailable: block. - Candidate quote has unsupported assets: reject with `unsupported_pair`.
- Requested amount exceeds spendable EURe: block. - Source inventory is insufficient: keep `insufficient_inventory`, not `inventory_skew_worsens`.
- Reference price stale: block. - Quote improves skew but does not clear base threshold: reject with a reason that says raw edge failed base threshold.
- Slippage missing: block. - Recent outcomes are all submitted-only: outcome confidence is unknown, not good.
- Duplicate idempotency key: return original result, do not submit again. - Recent movement is heuristic: count separately from linked terminal settlement.
- Relay timeout: failed or unknown state with durable reason, not completed.
- Relay accepted but no inventory movement: awaiting outcome, then not filled after evidence window.
- Partial fill, if supported: represent explicitly; otherwise block or mark ambiguous until semantics are known.
## Concrete implementation order ## Concrete implementation order
### Phase 1. Protocol verification and model ### Phase 1. Model and tests
- Inspect primary NEAR Intents request API evidence and current repo clients. - Add pure helper functions for inventory value mix, projected post-trade mix, direction classification, and effective threshold.
- Decide endpoint/method and payload shape. - Add tests for improving, neutral, and worsening inventory directions.
- Add request lifecycle constants and schemas. - Add tests that threshold never drops below `1.49`.
- Add tests for semantic invariants independent of live API.
### Phase 2. Preflight path ### Phase 2. Strategy integration
- Implement pure preflight helper for EURe-to-BTC exact-in requests. - Wire helpers into `src/core/strategy.mjs` and `src/apps/strategy-engine.mjs`.
- Wire inventory, reference price, signer registration, amount, slippage, and deadline checks. - Extend emitted decision payloads with policy fields.
- Add tests for success, insufficient inventory, stale price, stale inventory, zero amount, and missing signer. - Preserve existing execution command shape unless size-limiting is implemented.
### Phase 3. Signing and submit client ### Phase 3. Outcome-confidence integration
- Implement taker request envelope/signing helper. - Load or derive recent outcome counts from existing quote outcome records where the strategy process can access them.
- Implement relay/API client method with timeout and error normalization. - 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 deterministic signing tests and mocked client submission tests. - Add regression tests for submitted-only counts.
### Phase 4. Durable execution path ### Phase 4. Operator surfaces
- Add request submit command/result event routes and persistence. - Update dashboard bootstrap and Strategy page to render the new policy fields.
- Add idempotency guard. - Ensure no operator-facing `Actionable` label returns.
- Add submission failure and duplicate-submit tests. - Ensure no submitted-only row is described as completed or successful.
### Phase 5. Outcome truth ### Phase 5. Deploy and validate
- Extend request outcome attribution using inventory deltas. - Run targeted tests plus full `npm test`.
- Add tests for submitted-not-completed, accepted-not-completed, completed with exact settlement, not-filled after deadline, and ambiguous movement. - Build the dashboard bundle.
### Phase 6. Operator UI
- Add preflight/submit controls and request lifecycle table.
- Add copy affordances for request and relay ids.
- Add dashboard tests proving no submitted-only request is labeled successful.
### Phase 7. Deploy and validate
- Run targeted tests plus full npm test.
- Build dashboard bundle.
- Commit with required proof body. - Commit with required proof body.
- Push to forgejo/main. - Push to `forgejo/main`.
- Validate rollout image, service state, dashboard bootstrap, and live dry-run/preflight. - Validate rollout image, strategy state, executor state, dashboard bootstrap, and at least one recent decision carrying inventory-policy fields.
- If operator explicitly submits live, validate durable request row, submission result, and later settlement or no-fill.
## Test plan ## Test plan
- Request preflight unit tests. - Unit tests for inventory-skew direction.
- Request signing/envelope tests. - Unit tests for effective threshold calculation.
- Request client timeout/failure tests. - Unit tests for missing inputs and insufficient inventory reason precedence.
- Idempotency tests. - Dashboard tests for base/effective threshold rendering.
- Persistence routing tests. - Negative tests:
- Outcome attribution tests. - submitted-only outcome count does not improve fill confidence
- Dashboard semantic tests. - inventory-skew comparison is not labeled realized PnL
- Negative tests: submitted != completed; relay accepted != completed; pending EURe cannot be spent; dry-run cannot submit; duplicate submit does not call relay twice; request lifecycle cannot be confused with incoming quote response lifecycle. - threshold below `1.49` is rejected or clamped unless explicitly configured in a test-only override
## Validation checklist against the proof ## Validation checklist against the proof
- /state or dashboard shows request preflight capability and current spendable EURe. - Live strategy `/state` shows decisions with inventory-policy fields.
- A dry-run EURe-to-BTC request can be produced without side effects. - Dashboard Strategy page can explain a quote that passed raw edge but was withheld or size-limited by inventory policy.
- A live submit path exists only behind explicit operator action. - Dashboard Strategy page can explain a quote that improves inventory and clears base threshold.
- Durable request lifecycle rows exist and are visible with copyable ids. - Executor remains armed if it was armed before deployment.
- Settlement outcome remains truthful after submission. - The repo still deploys fully from push without manual cluster reconciliation.
- All services deploy from repo push without manual cluster reconciliation.
## Known fakes allowed at start of this turn ## Known fakes allowed at start of this turn
- Request API method is not yet verified. - Realized net PnL remains unavailable without fee/cost attribution.
- Venue-native terminal fill events remain unavailable unless the request API exposes them. - Venue-native terminal fill events remain unavailable.
- Fee-complete realized PnL remains unavailable. - Outcome-confidence may be dashboard-only if strategy DB access is not justified in the implementation.
- Automatic portfolio optimization remains unavailable.

186
PROOF.md
View file

@ -1,133 +1,121 @@
# Implementation Proof: NEAR Intents request creation and EURe-to-BTC taker flow # Implementation Proof: settlement-aware strategy and inventory-skew controls
Status: open Status: open
Opened: 2026-04-12 Opened: 2026-04-10
## Target outcome ## Target outcome
The repository must be able to create our own NEAR Intents EURe-to-BTC swap request from credited internal inventory, submit it through repo-owned code, and explain the full request lifecycle from preflight through settlement truth. The strategy should stop behaving like a one-dimensional edge filter and start making inventory-aware choices that are explainable from durable data.
For each repo-created request the operator must be able to answer: For each live BTC/EURe quote the operator must be able to answer:
- which asset and amount we intended to spend - whether the quote was attractive on raw reference edge
- which asset and minimum amount we expected to receive - whether trading that side improves or worsens the current inventory skew
- which signer, verifier contract, nonce, deadline, slippage, and idempotency key were used - whether the threshold used for that quote was the base threshold or an inventory-adjusted threshold
- whether the request was drafted, blocked, submitted, accepted by relay, failed, awaiting settlement, not filled, or completed - whether recent settlement outcomes support or weaken confidence in submitting more quotes on that side
- whether completed means durable inventory movement, not relay acceptance - why the strategy withheld, approved, or size-limited the quote
- how much BTC was received and how much EURe was spent, if settlement is proven
## Why this is the next architecture test ## Why this is the next architecture test
The existing system can observe incoming NEAR Intents quote requests and respond as a solver or maker. That path has not produced fills at 1.49%, 0.99%, or 0.49% in recent live validation, and it cannot intentionally convert our EURe inventory into BTC. The previous turn made submission, not-fill, and settlement-attributed completion visible. It proved that the repo can now distinguish accepted quote responses from actual asset movement.
The next false path would be manually moving funds or adding a button that submits opaque live requests without durable preflight, request, and settlement evidence. This turn is successful only if the system can create requests as a first-class, auditable repo-owned flow instead of treating live fund movement as an off-system action. The next false path is strategy behavior that ignores that truth:
- a quote may clear the raw 1.49% edge but move inventory further away from the preferred BTC/EURe mix
- the opposite side may be blocked by inventory, stale price, or poor recent fill evidence
- portfolio-vs-hold movement is still not realized trade PnL and must not be used as if it were
- simply lowering the edge threshold further would be risk widening without proof
This turn is successful only if strategy decisions become reproducible from explicit edge, inventory-skew, and settlement-outcome inputs.
## Scope ## Scope
- [I017] Repo-owned NEAR Intents request creation and EURe-to-BTC taker flow: create, sign, submit, and settle our own swap requests from credited inventory with truthful dashboard evidence. tags=intents,taker,execution,inventory,settlement - [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.
- Active venue only: NEAR Intents. - Active venue and pair only: NEAR Intents BTC/EURe.
- Active direction: credited internal EURe to BTC. - Preserve the approved base edge threshold of `1.49%` unless the user explicitly approves a different value.
- Use credited spendable internal inventory only. Pending funding remains non-spendable. - Preserve the current max notional unless the user explicitly approves a different value.
- Build the request path with dry-run/preflight first, then gated live submission. - Use existing durable portfolio metrics, inventory snapshots, reference prices, decisions, commands, execution results, and quote outcome attributions.
- Actual live submission requires explicit operator control and must be recorded durably.
## Assumptions ## Assumptions
- NEAR Intents exposes a supported request or quote publication method through the solver relay or another documented endpoint callable with our existing API key and verifier signer. - The current BTC/EURe inventory mix has a preferred target or policy that can be encoded with repo-owned config.
- The correct taker intent can be represented as a signed verifier token_diff payload or a documented request envelope whose semantics can be proven before live submission. - The first inventory policy can be simple and explicit, for example target BTC value percentage plus a tolerance band.
- Internal inventory snapshots are fresh enough to enforce spendable EURe and settlement deltas. - Quote outcome records are good enough to compute side-level recent submission, not-fill, and completion counts, while remaining honest about heuristic settlement attribution.
- BTC minimum receive can be derived from reference price plus explicit slippage or minimum-out policy. - Benchmark comparisons can guide strategy but are not realized PnL.
- The user's intent is to build the capability to move EURe into BTC; live all-EURe execution remains behind an explicit final operator action in the repo-owned UI or API.
## Turn-shaping rules ## Turn-shaping rules
- Do not manually move funds. - Do not lower `STRATEGY_GROSS_THRESHOLD_PCT` below `1.49` in this turn without explicit user approval.
- Do not submit an all-EURe live request until repo-owned preflight, durable request logging, and settlement attribution are implemented and the operator explicitly triggers that live request. - Do not increase `STRATEGY_MAX_NOTIONAL_EURE` in this turn without explicit user approval.
- Do not use pending or uncredited EURe. - Do not add live funds or move funds.
- Do not label relay acceptance as completed settlement. - Do not claim inventory-skew benefit as realized profit.
- Do not hide slippage, minimum receive, deadline, nonce, signer, or request id. - Do not hide a base-threshold pass behind a generic rejection; expose the decisive strategy reason.
- If the NEAR Intents request API cannot be verified from primary evidence or live dry-run behavior, stop and record the blocker instead of inventing a protocol. - If recent outcome confidence is used, show the window and counts behind it.
- Keep maker quote-response logic intact unless the new taker flow proves it should be paused or separated.
## Non-goals ## Non-goals
- No new venue. - No new venue integration.
- No external wallet or manual bridge action. - No new treasury fee ledger.
- No automatic recurring rebalancer. - No generalized optimizer or ML strategy.
- No realized net PnL claim without fee and cost attribution. - No broad backtesting workbench.
- No tax or accounting treatment. - No tax, accounting, or realized net PnL claims.
- No broad multi-asset request builder beyond EURe-to-BTC. - No automatic funding, withdrawal, or treasury rebalancing.
## Required operator behavior ## Required operator behavior
### Request preflight truth ### Strategy threshold truth
Before submission, the operator must see: Every recent strategy decision must expose:
- spendable EURe available - base threshold
- requested EURe spend amount - effective threshold
- BTC reference price - inventory adjustment, if any
- slippage or minimum-out rule - outcome-confidence adjustment, if any
- expected BTC receive and minimum BTC receive - final decisive reason
- deadline and nonce policy
- exact signer account and verifier contract
- whether this is dry-run only or live-submit capable
### Request lifecycle truth ### Inventory-skew truth
For each repo-created request, the dashboard must show: For every quote decision the dashboard must show:
- request id, copyable - current BTC and EURe spendable value
- idempotency key, copyable - target BTC/EURe value mix or configured policy
- intent hash or relay request id if returned, copyable - current skew versus target
- created_at, submitted_at, resolved_at if known - whether the proposed trade moves inventory toward or away from target
- state: draft, blocked, submitted, accepted_by_relay, failed, awaiting_settlement, not_filled, completed
- decisive reason for blocks, failures, or no-fill
- settlement evidence if completed
### Settlement truth ### Outcome-confidence truth
Completed requires durable asset movement evidence: If recent quote outcomes influence approval or threshold:
- EURe spend delta and BTC receive delta from inventory snapshots - submitted-only rows must not count as completed
- attribution method and caveat if heuristic - not-filled rows must be separate from strategy rejections and executor blocks
- submitted-only and relay-accepted rows remain separate from completed - heuristic completed rows must be counted as heuristic, not venue-terminal fills
- portfolio-vs-hold movement remains separate from realized trade PnL
## Semantic invariants ## Semantic invariants
The implementation and tests must enforce at least: The implementation and tests must enforce at least:
- request submitted != completed - `submitted` outcome evidence cannot improve fill-confidence as if completed
- relay accepted != settled inventory movement - inventory-skew improvement is not realized PnL
- pending EURe cannot be spent - base edge and effective edge must both be visible when they differ
- insufficient spendable EURe blocks before signing or submission - insufficient inventory remains distinct from inventory-skew rejection
- slippage and minimum-out must be explicit and persisted - strategy rejection remains distinct from executor blocking
- duplicate idempotency key cannot produce duplicate live submissions - no threshold lower than `1.49%` is deployed without explicit approval
- dry-run request cannot accidentally submit
- completed request rows require durable settlement evidence
- request-creation flow is distinct from incoming quote-response flow
## Definition of done ## Definition of done
- The repo contains a verified NEAR Intents request-creation client or a recorded blocker proving the venue path is unavailable. - Strategy decisions include explicit inventory-skew inputs and effective threshold fields.
- A request preflight API computes amount, min-out, deadline, nonce policy, signer, verifier, and inventory checks from durable/current data. - The strategy can approve, reject, or size-limit a quote based on inventory direction with a decisive reason.
- A gated live submission API exists only after preflight and records durable request, submission, and result events. - Dashboard lifecycle or strategy rows show raw edge, effective threshold, skew direction, and decisive reason.
- The dashboard shows repo-created request rows separately from incoming quote-response rows, with copyable ids and lifecycle reasons. - Recent outcome counts are available to the strategy or dashboard without treating submission-only rows as fills.
- Settlement attribution handles repo-created requests without treating relay acceptance as completion. - Regression tests cover inventory-skew direction, threshold adjustment, and the negative semantic invariants.
- Regression tests cover request signing/envelope semantics, inventory blocks, dry-run safety, idempotency, submission failure, submitted-not-completed, and completed-only-with-settlement. - The result is deployed through the repo workflow and validated against live service state and dashboard bootstrap data.
- The result is deployed through the repo workflow and validated against live service state.
## Validation evidence required ## Validation evidence required
- Unit tests for request preflight and minimum-out/slippage math. - Automated tests for strategy decisions that pass raw edge but fail inventory-skew policy.
- Unit tests for signed request or request envelope construction using deterministic signer fixtures. - Automated tests for strategy decisions where inventory improvement lowers friction or preserves the base threshold without lowering below `1.49%`.
- Unit tests proving insufficient EURe blocks before signing/submission. - Automated tests proving submitted-only outcomes do not improve completion confidence.
- Unit tests proving submitted/accepted requests do not count as completed without inventory deltas. - Live dashboard or `/state` evidence showing strategy decisions with base threshold, effective threshold, inventory skew, and decisive reason.
- Live dry-run/preflight evidence for current credited EURe inventory. - Live evidence that strategy and executor remain armed after deployment if they were armed before rollout.
- If live submission is explicitly triggered, durable DB evidence for request, submission result, and later settlement or no-fill.
- Dashboard bootstrap evidence showing the new request lifecycle row with copyable ids and truthful state.
## Failure conditions ## Failure conditions
- Live funds are moved outside repo-owned code. - The strategy still emits only `actionable` or `insufficient_inventory` without inventory-policy evidence.
- A request is submitted without durable preflight and request records. - The dashboard cannot explain why a raw-edge quote was withheld by inventory policy.
- The UI claims BTC was bought from relay acceptance alone. - A submitted quote is treated as a completed or successful trade in any strategy confidence calculation.
- A dry-run path can submit. - Benchmark or inventory-skew deltas are labeled as realized PnL.
- Pending funding is treated as spendable. - The deployed threshold is lower than `1.49%` without explicit user approval.
- The implementation cannot prove the NEAR Intents request API shape and still proceeds.
## Current real before this turn ## Current real before this turn
- The repo has verifier signing for quote-response token_diff payloads. - Live quote, decision, command, submission result, and quote outcome attribution records are durable.
- The repo has a solver relay websocket client and quote-response submission path. - The dashboard separates submitted, rejected, blocked, not-filled, and completed rows.
- Credited internal BTC/EURe inventory is synced durably. - One historical quote is linked to a heuristic settled inventory delta.
- Quote, decision, command, submission result, and outcome attribution records exist for incoming quote-response flow. - Recent submitted-only rows are visible without claiming asset movement.
- The dashboard distinguishes submitted, not-filled, completed, rejected, and blocked rows for incoming quote responses. - Portfolio-vs-simple-hold comparison is cash-flow adjusted and explicitly not realized PnL.
## Deliberately not built by this proof ## Deliberately not built by this proof
- General portfolio optimizer. - Full fee and cost attribution.
- Automatic all-in rebalancing loop. - Venue-native terminal fill ingestion.
- Fee-complete realized PnL. - Automatic inventory rebalancing outside quote-response execution.
- Venue-native terminal fill ingestion unless the request API provides it directly. - Broader research/backtest UI.

View file

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

View file

@ -1,121 +0,0 @@
# Implementation Proof: settlement-aware strategy and inventory-skew controls
Status: open
Opened: 2026-04-10
## Target outcome
The strategy should stop behaving like a one-dimensional edge filter and start making inventory-aware choices that are explainable from durable data.
For each live BTC/EURe quote the operator must be able to answer:
- whether the quote was attractive on raw reference edge
- whether trading that side improves or worsens the current inventory skew
- whether the threshold used for that quote was the base threshold or an inventory-adjusted threshold
- whether recent settlement outcomes support or weaken confidence in submitting more quotes on that side
- why the strategy withheld, approved, or size-limited the quote
## Why this is the next architecture test
The previous turn made submission, not-fill, and settlement-attributed completion visible. It proved that the repo can now distinguish accepted quote responses from actual asset movement.
The next false path is strategy behavior that ignores that truth:
- a quote may clear the raw 1.49% edge but move inventory further away from the preferred BTC/EURe mix
- the opposite side may be blocked by inventory, stale price, or poor recent fill evidence
- portfolio-vs-hold movement is still not realized trade PnL and must not be used as if it were
- simply lowering the edge threshold further would be risk widening without proof
This turn is successful only if strategy decisions become reproducible from explicit edge, inventory-skew, and settlement-outcome inputs.
## Scope
- [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.
- Active venue and pair only: NEAR Intents BTC/EURe.
- Preserve the approved base edge threshold of `1.49%` unless the user explicitly approves a different value.
- Preserve the current max notional unless the user explicitly approves a different value.
- Use existing durable portfolio metrics, inventory snapshots, reference prices, decisions, commands, execution results, and quote outcome attributions.
## Assumptions
- The current BTC/EURe inventory mix has a preferred target or policy that can be encoded with repo-owned config.
- The first inventory policy can be simple and explicit, for example target BTC value percentage plus a tolerance band.
- Quote outcome records are good enough to compute side-level recent submission, not-fill, and completion counts, while remaining honest about heuristic settlement attribution.
- Benchmark comparisons can guide strategy but are not realized PnL.
## Turn-shaping rules
- Do not lower `STRATEGY_GROSS_THRESHOLD_PCT` below `1.49` in this turn without explicit user approval.
- Do not increase `STRATEGY_MAX_NOTIONAL_EURE` in this turn without explicit user approval.
- Do not add live funds or move funds.
- Do not claim inventory-skew benefit as realized profit.
- Do not hide a base-threshold pass behind a generic rejection; expose the decisive strategy reason.
- If recent outcome confidence is used, show the window and counts behind it.
## Non-goals
- No new venue integration.
- No new treasury fee ledger.
- No generalized optimizer or ML strategy.
- No broad backtesting workbench.
- No tax, accounting, or realized net PnL claims.
- No automatic funding, withdrawal, or treasury rebalancing.
## Required operator behavior
### Strategy threshold truth
Every recent strategy decision must expose:
- base threshold
- effective threshold
- inventory adjustment, if any
- outcome-confidence adjustment, if any
- final decisive reason
### Inventory-skew truth
For every quote decision the dashboard must show:
- current BTC and EURe spendable value
- target BTC/EURe value mix or configured policy
- current skew versus target
- whether the proposed trade moves inventory toward or away from target
### Outcome-confidence truth
If recent quote outcomes influence approval or threshold:
- submitted-only rows must not count as completed
- not-filled rows must be separate from strategy rejections and executor blocks
- heuristic completed rows must be counted as heuristic, not venue-terminal fills
## Semantic invariants
The implementation and tests must enforce at least:
- `submitted` outcome evidence cannot improve fill-confidence as if completed
- inventory-skew improvement is not realized PnL
- base edge and effective edge must both be visible when they differ
- insufficient inventory remains distinct from inventory-skew rejection
- strategy rejection remains distinct from executor blocking
- no threshold lower than `1.49%` is deployed without explicit approval
## Definition of done
- Strategy decisions include explicit inventory-skew inputs and effective threshold fields.
- The strategy can approve, reject, or size-limit a quote based on inventory direction with a decisive reason.
- Dashboard lifecycle or strategy rows show raw edge, effective threshold, skew direction, and decisive reason.
- Recent outcome counts are available to the strategy or dashboard without treating submission-only rows as fills.
- Regression tests cover inventory-skew direction, threshold adjustment, and the negative semantic invariants.
- The result is deployed through the repo workflow and validated against live service state and dashboard bootstrap data.
## Validation evidence required
- Automated tests for strategy decisions that pass raw edge but fail inventory-skew policy.
- Automated tests for strategy decisions where inventory improvement lowers friction or preserves the base threshold without lowering below `1.49%`.
- Automated tests proving submitted-only outcomes do not improve completion confidence.
- Live dashboard or `/state` evidence showing strategy decisions with base threshold, effective threshold, inventory skew, and decisive reason.
- Live evidence that strategy and executor remain armed after deployment if they were armed before rollout.
## Failure conditions
- The strategy still emits only `actionable` or `insufficient_inventory` without inventory-policy evidence.
- The dashboard cannot explain why a raw-edge quote was withheld by inventory policy.
- A submitted quote is treated as a completed or successful trade in any strategy confidence calculation.
- Benchmark or inventory-skew deltas are labeled as realized PnL.
- The deployed threshold is lower than `1.49%` without explicit user approval.
## Current real before this turn
- Live quote, decision, command, submission result, and quote outcome attribution records are durable.
- The dashboard separates submitted, rejected, blocked, not-filled, and completed rows.
- One historical quote is linked to a heuristic settled inventory delta.
- Recent submitted-only rows are visible without claiming asset movement.
- Portfolio-vs-simple-hold comparison is cash-flow adjusted and explicitly not realized PnL.
## Deliberately not built by this proof
- Full fee and cost attribution.
- Venue-native terminal fill ingestion.
- Automatic inventory rebalancing outside quote-response execution.
- Broader research/backtest UI.