Prompt T0.2 — Precompute pairing arithmetic in the prompt; the model echoes amounts, never derives them
Part of prompt-building Tier 0. Principle: the model echoes; deterministic code computes.
Why
The shipped virtualAmounts set both the price (their ratio) and the depth (their size) — grammar.ts COMPAT_RULES states this, and then leaves the arithmetic to the model: to ship WETH/USDC near mid, the model must divide the USDC budget by the mid price, across two different decimal scales. That is silent-failure territory for a 7B model, and a wrong ratio is not a cosmetic bug — it ships a strategy priced off-mid, which is an instant-arb gift to the first taker. Nothing in the validator catches it today (a price-vs-mid invariant is planned for Tier 2; this issue closes most of the gap at the prompt level first).
What
- A pure helper (suggested home:
packages/arbitration-sdk/src/context.ts next to contextPromptBlock, or its own module):
// Render exact value-matched conversions for the budget tokens against the
// context pair's mid, as decimal strings. Pure; exact decimal/bigint math —
// no floats anywhere near a signed artifact.
export function pairingLines(ctx: MarketContext, budget: RecommendationRequest["budget"]): string[];
- Only render conversions for tokens that are actually in
ctx.pair — never fabricate a rate for a token the context has no mid for.
- Exact fixed-point math (bigint), display trimmed to a sensible precision (e.g. 6 significant fractional digits), tests assert exact strings.
- The context block already labels the pair data as STUB (F3 job 2 / Open Q2) — these lines inherit that honesty automatically by living under it.
- Rendered into the compose prompt's context section:
REFERENCE CONVERSIONS (computed for you — echo these, do NOT do your own arithmetic):
at mid 3450 USDC/WETH: 1000 USDC ≙ 0.289855 WETH | 0.5 WETH ≙ 1725 USDC
The ratio of a strategy's virtualAmounts IS its shipped price. Keep that ratio
consistent with the mid above unless the user's own words explicitly ask for an
off-mid price.
- When T0.3 (three tiers) is in play, extend the same helper to render the per-strategy split amounts (e.g. thirds of the budget, value-matched per side) so the model can satisfy I2 (per-token sum across ALL strategies ≤ budget) by copying numbers instead of dividing. The
compose.ts history note is explicit that "a model split a budget across strategies by adding rather than dividing" is the expected failure — don't let it do either.
Acceptance criteria
Coordination
Prompt-refactor PR in flight — same note as T0.1: helper is safe now, wire the rendering into whichever builder survives, bump PROMPT_VERSION if the app-side contract (packages/app/src/lib/compose/prompt.ts) is the integration point.
References
Prompt T0.2 — Precompute pairing arithmetic in the prompt; the model echoes amounts, never derives them
Part of prompt-building Tier 0. Principle: the model echoes; deterministic code computes.
Why
The shipped
virtualAmountsset both the price (their ratio) and the depth (their size) —grammar.tsCOMPAT_RULES states this, and then leaves the arithmetic to the model: to ship WETH/USDC near mid, the model must divide the USDC budget by the mid price, across two different decimal scales. That is silent-failure territory for a 7B model, and a wrong ratio is not a cosmetic bug — it ships a strategy priced off-mid, which is an instant-arb gift to the first taker. Nothing in the validator catches it today (a price-vs-mid invariant is planned for Tier 2; this issue closes most of the gap at the prompt level first).What
packages/arbitration-sdk/src/context.tsnext tocontextPromptBlock, or its own module):ctx.pair— never fabricate a rate for a token the context has no mid for.compose.tshistory note is explicit that "a model split a budget across strategies by adding rather than dividing" is the expected failure — don't let it do either.Acceptance criteria
pairingLinesis pure and exact: unit tests cover both directions of the pair, decimal-scale differences (6 vs 18), a budget token absent from the pair (renders nothing for it), and rounding/trim behaviour.0.1-style repeats).Coordination
Prompt-refactor PR in flight — same note as T0.1: helper is safe now, wire the rendering into whichever builder survives, bump
PROMPT_VERSIONif the app-side contract (packages/app/src/lib/compose/prompt.ts) is the integration point.References
packages/arbitration-sdk/src/grammar.ts— COMPAT_RULES line on ratio-sets-price and decimal mismatchpackages/arbitration-sdk/src/validate.ts— I2 (the sum-across-strategies invariant the split amounts serve)