Compare commits

...

2 commits

Author SHA1 Message Date
philipp
55ece8f5f0 Open NEAR Intents request creation turn
All checks were successful
deploy / deploy (push) Successful in 34s
Proof: Archive index, implementation proof, and implementation plan now define the approved NEAR Intents EURe-to-BTC request-creation turn with explicit lifecycle, settlement, and safety invariants.

Assumptions: The next turn is approved by the operator and will verify the NEAR Intents request API before any live fund movement; all live submission remains behind repo-owned preflight and explicit operator action.

Still fake: Request API shape is not yet verified, repo-owned request submission is not implemented, and no EURe-to-BTC live request has been created by this planning commit.
2026-04-12 17:39:21 +02:00
philipp
52505a4257 Archive implementation turn: settlement-aware strategy and inventory-skew controls
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-12 17:35:16 +02:00
5 changed files with 483 additions and 192 deletions

View file

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

186
PROOF.md
View file

@ -1,121 +1,133 @@
# Implementation Proof: settlement-aware strategy and inventory-skew controls # Implementation Proof: NEAR Intents request creation and EURe-to-BTC taker flow
Status: open Status: open
Opened: 2026-04-10 Opened: 2026-04-12
## Target outcome ## 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. 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.
For each live BTC/EURe quote the operator must be able to answer: For each repo-created request the operator must be able to answer:
- whether the quote was attractive on raw reference edge - which asset and amount we intended to spend
- whether trading that side improves or worsens the current inventory skew - which asset and minimum amount we expected to receive
- whether the threshold used for that quote was the base threshold or an inventory-adjusted threshold - which signer, verifier contract, nonce, deadline, slippage, and idempotency key were used
- whether recent settlement outcomes support or weaken confidence in submitting more quotes on that side - whether the request was drafted, blocked, submitted, accepted by relay, failed, awaiting settlement, not filled, or completed
- why the strategy withheld, approved, or size-limited the quote - whether completed means durable inventory movement, not relay acceptance
- 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 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 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 next false path is strategy behavior that ignores that truth: 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.
- 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
- [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. - [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
- Active venue and pair only: NEAR Intents BTC/EURe. - Active venue only: NEAR Intents.
- Preserve the approved base edge threshold of `1.49%` unless the user explicitly approves a different value. - Active direction: credited internal EURe to BTC.
- Preserve the current max notional unless the user explicitly approves a different value. - Use credited spendable internal inventory only. Pending funding remains non-spendable.
- Use existing durable portfolio metrics, inventory snapshots, reference prices, decisions, commands, execution results, and quote outcome attributions. - Build the request path with dry-run/preflight first, then gated live submission.
- Actual live submission requires explicit operator control and must be recorded durably.
## Assumptions ## Assumptions
- The current BTC/EURe inventory mix has a preferred target or policy that can be encoded with repo-owned config. - 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 first inventory policy can be simple and explicit, for example target BTC value percentage plus a tolerance band. - 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.
- Quote outcome records are good enough to compute side-level recent submission, not-fill, and completion counts, while remaining honest about heuristic settlement attribution. - Internal inventory snapshots are fresh enough to enforce spendable EURe and settlement deltas.
- Benchmark comparisons can guide strategy but are not realized PnL. - BTC minimum receive can be derived from reference price plus explicit slippage or minimum-out policy.
- 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 lower `STRATEGY_GROSS_THRESHOLD_PCT` below `1.49` in this turn without explicit user approval. - Do not manually move funds.
- Do not increase `STRATEGY_MAX_NOTIONAL_EURE` 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 add live funds or move funds. - Do not use pending or uncredited EURe.
- Do not claim inventory-skew benefit as realized profit. - Do not label relay acceptance as completed settlement.
- Do not hide a base-threshold pass behind a generic rejection; expose the decisive strategy reason. - Do not hide slippage, minimum receive, deadline, nonce, signer, or request id.
- If recent outcome confidence is used, show the window and counts behind it. - 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.
- 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 integration. - No new venue.
- No new treasury fee ledger. - No external wallet or manual bridge action.
- No generalized optimizer or ML strategy. - No automatic recurring rebalancer.
- No broad backtesting workbench. - No realized net PnL claim without fee and cost attribution.
- No tax, accounting, or realized net PnL claims. - No tax or accounting treatment.
- No automatic funding, withdrawal, or treasury rebalancing. - No broad multi-asset request builder beyond EURe-to-BTC.
## Required operator behavior ## Required operator behavior
### Strategy threshold truth ### Request preflight truth
Every recent strategy decision must expose: Before submission, the operator must see:
- base threshold - spendable EURe available
- effective threshold - requested EURe spend amount
- inventory adjustment, if any - BTC reference price
- outcome-confidence adjustment, if any - slippage or minimum-out rule
- final decisive reason - expected BTC receive and minimum BTC receive
- deadline and nonce policy
- exact signer account and verifier contract
- whether this is dry-run only or live-submit capable
### Inventory-skew truth ### Request lifecycle truth
For every quote decision the dashboard must show: For each repo-created request, the dashboard must show:
- current BTC and EURe spendable value - request id, copyable
- target BTC/EURe value mix or configured policy - idempotency key, copyable
- current skew versus target - intent hash or relay request id if returned, copyable
- whether the proposed trade moves inventory toward or away from target - created_at, submitted_at, resolved_at if known
- 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
### Outcome-confidence truth ### Settlement truth
If recent quote outcomes influence approval or threshold: Completed requires durable asset movement evidence:
- submitted-only rows must not count as completed - EURe spend delta and BTC receive delta from inventory snapshots
- not-filled rows must be separate from strategy rejections and executor blocks - attribution method and caveat if heuristic
- heuristic completed rows must be counted as heuristic, not venue-terminal fills - submitted-only and relay-accepted rows remain separate from completed
- 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:
- `submitted` outcome evidence cannot improve fill-confidence as if completed - request submitted != completed
- inventory-skew improvement is not realized PnL - relay accepted != settled inventory movement
- base edge and effective edge must both be visible when they differ - pending EURe cannot be spent
- insufficient inventory remains distinct from inventory-skew rejection - insufficient spendable EURe blocks before signing or submission
- strategy rejection remains distinct from executor blocking - slippage and minimum-out must be explicit and persisted
- no threshold lower than `1.49%` is deployed without explicit approval - duplicate idempotency key cannot produce duplicate live submissions
- 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
- Strategy decisions include explicit inventory-skew inputs and effective threshold fields. - The repo contains a verified NEAR Intents request-creation client or a recorded blocker proving the venue path is unavailable.
- The strategy can approve, reject, or size-limit a quote based on inventory direction with a decisive reason. - A request preflight API computes amount, min-out, deadline, nonce policy, signer, verifier, and inventory checks from durable/current data.
- Dashboard lifecycle or strategy rows show raw edge, effective threshold, skew direction, and decisive reason. - A gated live submission API exists only after preflight and records durable request, submission, and result events.
- Recent outcome counts are available to the strategy or dashboard without treating submission-only rows as fills. - The dashboard shows repo-created request rows separately from incoming quote-response rows, with copyable ids and lifecycle reasons.
- Regression tests cover inventory-skew direction, threshold adjustment, and the negative semantic invariants. - Settlement attribution handles repo-created requests without treating relay acceptance as completion.
- The result is deployed through the repo workflow and validated against live service state and dashboard bootstrap data. - 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.
## Validation evidence required ## Validation evidence required
- Automated tests for strategy decisions that pass raw edge but fail inventory-skew policy. - Unit tests for request preflight and minimum-out/slippage math.
- Automated tests for strategy decisions where inventory improvement lowers friction or preserves the base threshold without lowering below `1.49%`. - Unit tests for signed request or request envelope construction using deterministic signer fixtures.
- Automated tests proving submitted-only outcomes do not improve completion confidence. - Unit tests proving insufficient EURe blocks before signing/submission.
- Live dashboard or `/state` evidence showing strategy decisions with base threshold, effective threshold, inventory skew, and decisive reason. - Unit tests proving submitted/accepted requests do not count as completed without inventory deltas.
- Live evidence that strategy and executor remain armed after deployment if they were armed before rollout. - Live dry-run/preflight evidence for current credited EURe inventory.
- 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
- The strategy still emits only `actionable` or `insufficient_inventory` without inventory-policy evidence. - Live funds are moved outside repo-owned code.
- The dashboard cannot explain why a raw-edge quote was withheld by inventory policy. - A request is submitted without durable preflight and request records.
- A submitted quote is treated as a completed or successful trade in any strategy confidence calculation. - The UI claims BTC was bought from relay acceptance alone.
- Benchmark or inventory-skew deltas are labeled as realized PnL. - A dry-run path can submit.
- The deployed threshold is lower than `1.49%` without explicit user approval. - Pending funding is treated as spendable.
- The implementation cannot prove the NEAR Intents request API shape and still proceeds.
## Current real before this turn ## Current real before this turn
- Live quote, decision, command, submission result, and quote outcome attribution records are durable. - The repo has verifier signing for quote-response token_diff payloads.
- The dashboard separates submitted, rejected, blocked, not-filled, and completed rows. - The repo has a solver relay websocket client and quote-response submission path.
- One historical quote is linked to a heuristic settled inventory delta. - Credited internal BTC/EURe inventory is synced durably.
- Recent submitted-only rows are visible without claiming asset movement. - Quote, decision, command, submission result, and outcome attribution records exist for incoming quote-response flow.
- Portfolio-vs-simple-hold comparison is cash-flow adjusted and explicitly not realized PnL. - The dashboard distinguishes submitted, not-filled, completed, rejected, and blocked rows for incoming quote responses.
## Deliberately not built by this proof ## Deliberately not built by this proof
- Full fee and cost attribution. - General portfolio optimizer.
- Venue-native terminal fill ingestion. - Automatic all-in rebalancing loop.
- Automatic inventory rebalancing outside quote-response execution. - Fee-complete realized PnL.
- Broader research/backtest UI. - Venue-native terminal fill ingestion unless the request API provides it directly.

View file

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

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