Skip to content

fix: normalize wrapped equity fills - #1564

Closed
JuaniRios wants to merge 1 commit into
masterfrom
rai-2666-normalize-wrapped-equity-fills
Closed

JuaniRios wants to merge 1 commit into
masterfrom
rai-2666-normalize-wrapped-equity-fills

Conversation

@JuaniRios

@JuaniRios JuaniRios commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

The bot now converts each wrapped Raindex fill into underlying shares, at the ERC-4626 (tokenized vault) ratio of the fill's block, before it updates the Position and hedges. Today it assumes 1 wrapped share equals 1 broker share, so it under-hedges SGOV, and P&L counts the wrapper's yield as a trading loss. RAI-2666

Live effect: hedge sizes change for every wrapper whose ratio is not 1 (larger for SGOV). P&L keeps counting pre-deploy fills 1:1, so pre-merge SGOV P&L stays about 1% off and new fills are exact · Risk: high (money path, stored data; no keys or IAM) · Ships: on the next release, deployed after market close

Decisions

  • Use the ratio at the fill's own block and fail closed, not fall back to the latest ratio or 1:1. A fallback hedges the wrong size with no signal. trade.rs
  • P&L keeps counting fills recorded before this change 1:1 in wrapped shares, and warns when a report's range includes them for a symbol not proven 1:1 (in practice, SGOV). That is exact for every ratio-1 wrapper and about 1% off for pre-merge SGOV. The alternative, marking those symbols unavailable, would blank all P&L history to fix SGOV's small error.
  • A fill that converts to zero underlying shares (dust at a ratio below 1, or any fill at a ratio of 0) goes to skipped_fills unhedged, not retried. A retry cannot succeed and would trip the conductor-wide fail-stop. conductor.rs

Risks

  • Every fill, not only SGOV, needs archive state at the fill's block from the accounting RPC. If the read fails, accounting stops before any Position write or hedge. It is a process-level error, so a lasting failure can stop hedging for every symbol. trade_accountant.rs
  • Startup now reads every equity's unwrapped token on every hedged chain, hedge-only chains too. It refuses to start if a read fails or the token is not 18 decimals. conductor.rs

Proof

  • A test books 2 wrapped shares at ratio 1.01 and 101 USDC as 2.02 shares at 100 USDC, the same 202 USDC. conductor.rs
  • I ran nix run .#prodVerifyMigrations on the first revision: the migration applies to a production snapshot and every stored event replays. The migration has not changed since, but the code has.
  • Not verified: no staging or live run on a wrapper whose ratio is not 1. The production accounting RPC was not checked for archive state; Base's public RPC does serve historical convertToAssets. All 54 unwrapped tokens the old startup probe skipped in the prod and staging configs report 18 decimals. Nobody rehearsed the flatten or tested a rollback.

Rollout

  1. Deploy after market close as normal. SGOV orders stop quoting after the close, so no fill lands during the deploy. Hedging is correct from the first fill after it.
  2. Optional, while the market is closed: correct the SGOV legacy residual, about 15.7 SGOV short from the old 1:1 hedging (computed from the 9,474 production fills at each day's ratio). Record a manual adjustment to net 0, then one to the real exposure in underlying shares with a price, so the bot hedges it at the open. Check the CLI's sign convention first. A manual adjustment places no broker order, and the Position rejects one while a hedge is pending.
  3. Cover any open TradingDisabled rows of wrapped symbols at the wrapped quantity × the ratio at the fill's block, not the recorded figure.
  4. Watch for ratio-read errors in the fill worker, Wrapper ratio changed within the fill's block warnings, and new zero_underlying_amount rows.
  5. Rollback: revert and release. Stored events replay under both versions, but the old binary books wrapped fills 1:1 again, so SGOV under-hedges again.

🤖 Generated with Claude Code

@linear-code

linear-code Bot commented Sep 25, 2026

Copy link
Copy Markdown

RAI-2666

Copy link
Copy Markdown
Collaborator Author

How to use the Graphite Merge Queue

Add the label add-to-gt-merge-queue to this PR to add it to the merge queue.

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@JuaniRios
JuaniRios force-pushed the rai-2666-normalize-wrapped-equity-fills branch from cae3e67 to 3698e79 Compare September 25, 2026 17:43
@JuaniRios

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai

coderabbitai Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Team

Run ID: f7ffff2f-10d2-4d60-b2a1-3d1df059e530

📥 Commits

Reviewing files that changed from the base of the PR and between 740ede7 and ab5eba9.

📒 Files selected for processing (3)
  • SPEC.md
  • src/dashboard/pnl/builder.rs
  • src/dashboard/pnl/tests.rs

Included review availability: This review used your included allowance. 4 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 6 reviews per hour.


Walkthrough

On-chain fills now use the wrapper ratio at the confirmed fill block to calculate underlying-share quantities and prices. Position events retain wrapped quantities and ratio evidence. Processing records zero-underlying fills as skipped and acknowledged, and resumes durable fills without rereading historical ratios. The P&L ledger stores ratio evidence and reports when legacy fills lack it. Inventory accounting uses wrapped quantities, and the dashboard labels on-chain quantities as wrapped shares.

Priority: ➖ Normal

Merge Risk: 🔵 Low · up to ab5eb

The wrapped-fill change looks safe in the reviewed P&L warning, spec and test edits. One earlier concern remains open: if recording a skipped fill fails, the fill may still be acknowledged and the reconciliation record lost. Owners should confirm or fix this before or soon after merge.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.83% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 164 functions across 24 files. (1 skipped… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: normalizing wrapped equity fills.
Description check ✅ Passed The description directly explains the fill normalization, ratio handling, P&L behavior, risks, testing, and rollout for the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 76.83% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 164 functions across 24 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🛠️ Fix failing CI checks 💡
  • Commit to this branch
  • Create a new PR

Comment @coderabbitai help to get the list of available commands.

@JuaniRios JuaniRios self-assigned this Sep 25, 2026
@JuaniRios

Copy link
Copy Markdown
Collaborator Author

@rain-marvin review

@rain-marvin

rain-marvin Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

🔎 Reviewing 3698e79, started by @JuaniRios. The review will appear here when it's done.

@rain-marvin rain-marvin Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Opus 5.5

This PR converts Raindex fills of ERC-4626 wrapped equities (for example SGOV) into underlying broker-share units before Position accounting and hedging. It reads the wrapper ratio at the fill block, keeps notional fixed, stores the ratio on OnChainFillApplied, and carries it into the P&L ledger. P&L marks symbols as unavailable when they have legacy fills with no recorded ratio.

The hedge-sizing fix is sound, and the fail-closed ratio read is the right idea. But the new underlying-unit amount also flows into consumers that still work in wrapped units, mainly the onchain inventory reactor and the trading-disabled cover instruction. The legacy P&L exclusion is also broader than SPEC.md describes: it hides every symbol traded before deploy, for every date range, with no path to recover, and the portfolio return is still computed from the partial result. I checked each finding below against the code at 3698e79.

Comment thread src/conductor.rs Outdated
Comment thread src/dashboard/pnl/builder.rs Outdated
Comment thread src/dashboard/pnl/builder.rs Outdated
Comment thread src/conductor.rs Outdated
Comment thread src/trading/onchain/trade_accountant.rs Outdated
@JuaniRios
JuaniRios force-pushed the rai-2666-normalize-wrapped-equity-fills branch 2 times, most recently from ac3039a to 05512af Compare September 28, 2026 20:08
@JuaniRios

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@JuaniRios

Copy link
Copy Markdown
Collaborator Author

@rain-marvin review

@rain-marvin

rain-marvin Bot commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

🔎 Reviewing 05512af, started by @JuaniRios. The review will appear here when it's done.

@coderabbitai

coderabbitai Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@rain-marvin rain-marvin Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Opus 5.5 (Codex 1)

This PR converts Raindex fills of ERC-4626 wrapped equities (for example SGOV) into underlying broker-share units before position accounting and hedging. It reads the wrapper ratio at the fill block, keeps the cash notional the same, and stores the ratio with the fill. P&L marks a symbol unavailable when it has legacy fills with no recorded ratio, unless a later zero manual adjustment proves that the position was flat.

At 05512af the fixes for the five earlier threads are all in place. The inventory slot stays in wrapped shares, the legacy cutover works, capital return is suppressed, the cover and process-tx outputs use broker units, and the accountant witnesses the fill before it reads the ratio. The hedge-sizing path is sound. The panel found nothing that blocks. Three minor items remain. The main one is that process-tx still reads the historical ratio before it witnesses and deduplicates the fill, so it does not match the accountant fix. The other two are the simulation fixture and the leftover legacy residual on existing positions.

Two other items were checked and left out. A legacy fill after toDate can mark an earlier range unavailable, but that range is pre-deploy and the check fails closed. convertToAssets(1e18) scaling can round down by dust.

Panel note: the Cursor Grok 4.6, composer 2.5, and flash 3.7 lanes could not run on this host because their CLIs are not authenticated. The review ran on opus 5.5 (general and deep lanes) and sol 5.6 (general and special lanes), which meets quorum.

Comment thread src/operator.rs Outdated
Comment thread src/position.rs
Comment thread src/conductor.rs
Comment thread src/position.rs
@JuaniRios
JuaniRios force-pushed the rai-2666-normalize-wrapped-equity-fills branch from 05512af to 6d8adcd Compare September 28, 2026 21:14
@JuaniRios

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@JuaniRios

Copy link
Copy Markdown
Collaborator Author

@rain-marvin review

@rain-marvin

rain-marvin Bot commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

🔎 Reviewing 6d8adcd, started by @JuaniRios. The review will appear here when it's done.

@coderabbitai

coderabbitai Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@rain-marvin rain-marvin Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Opus 5.5 (Cursor 1)

This PR converts fills of yield-bearing wrapped equities (for example SGOV) from wrapped shares into broker shares before position accounting and hedging, using the wrapper's convertToAssets ratio at the fill block. It keeps the raw wrapped fill for audit and in the onchain inventory slot, stores the ratio as evidence for P&L, and marks symbols with unproven legacy basis as unavailable until a manual zero adjustment proves they were flat.

Overall read: at 6d8adcd every earlier thread is fixed or accepted with a documented deploy step. The panel traced every consumer of the fill events (hedging, inventory reactor, P&L ledger and replay, performance projection, trading-disabled cover detail, process-tx) and found the units consistent. No blocking defects. Three minor items are below: a legacy fill after toDate wrongly marks an earlier range unavailable, the dashboard banner has no guard for version skew, and the ratio is read from end-of-block state.

A design note, not posted as a finding: storing the ratio on OnChainOrderFilled next to wrapped_amount (with a serde default), and not on OnChainFillApplied, would remove the ledger UPDATE, the second column and index, the CASE in the snapshot loader, and the MissingOnchainFillBasisTarget error that can stop ledger ingestion. It is worth considering before this schema becomes permanent.

Panel note: the Cursor Grok, composer, and flash lanes could not run because their CLIs were not authenticated. The review met quorum with the opus and sol lanes (two general lanes and three specialist lanes).

Comment thread src/dashboard/pnl/builder.rs Outdated
Comment thread dashboard/src/lib/components/pnl-panel.svelte Outdated
Comment thread src/onchain/trade.rs
@JuaniRios
JuaniRios force-pushed the rai-2666-normalize-wrapped-equity-fills branch from 6d8adcd to 9981d91 Compare September 28, 2026 21:40
@JuaniRios

Copy link
Copy Markdown
Collaborator Author

@rain-marvin review

@coderabbitai

coderabbitai Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@JuaniRios

Copy link
Copy Markdown
Collaborator Author

@rain-marvin approve

@rain-marvin

rain-marvin Bot commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

🔎 Verifying that my findings from a110b1b are addressed at acdd113, started by @JuaniRios. The review will appear here when it's done.

@rain-marvin rain-marvin Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Opus 5.5 (Claude 1)

This PR converts Raindex fills of ERC-4626 wrapped equities (for example SGOV) into underlying broker-share units before Position accounting and hedging. Onchain inventory stays in wrapped shares, each fill stores its proven fill-block ratio, and P&L marks legacy symbols unavailable until a zero manual adjustment proves the position was flat.

The review at a110b1b had no open findings. Since then, one commit (acdd113) addresses the three threads raised after it. I checked each one in the code at acdd113:

  • Zero wrapper ratio escalates to a process-wide stop (4137846066): resolved. normalized_fill_economics now returns ZeroUnderlyingAmount for a zero ratio before UnderlyingPerWrapped::new. skip_zero_underlying_fill runs before the trading-disabled branch in both the worker and process-tx, so the fill is recorded and acknowledged and does not fail on every retry. zero_wrapper_ratio_fill_is_skipped_and_acknowledged covers it.
  • Unpriced-adjustment check ran after the cutover was chosen (4137544344, resolved by the author): addressed. The check now runs inside the candidate loop, next to the crossing check, and only looks at rows that replay after the candidate. It also follows the replay's price rules: only an onchain fill or a priced nonzero adjustment sets a price, a zero adjustment is skipped, and offchain rows are ignored. That matches apply_manual_position_adjustment and apply_onchain_fill in replay.rs. The L, A0, unpriced A1, A2 test asserts that A2 is chosen.
  • Cutover warning did not name the blocking row (4137846084): resolved. Both checks now return the blocking rowid. The warning names it and says to hedge the real exposure at the broker before recording the new zero adjustment.

Threads resolved by hand, not by me:

  • 4137136443 (a ZeroUnderlyingAmount record did not replace a decode-time row): addressed. record_skipped_fill upserts over an earlier row with a different reason, keeps the old reason, event type, time and detail, and never replaces trading_disabled.
  • 4137136450 (an unpriced adjustment after a cutover failed the whole report): addressed. It now marks only that symbol unavailable and moves on to the next candidate, as described above.
  • 4128201006 (cutover replay-order crossings): case 1 addressed by replay_order_crosses_cutover, which checks both directions. Case 2 dismissed, and the dismissal holds. It is an existing ordering issue between adjustments and fills in ordered_position_events on master, it does not depend on wrapped basis, and it is going to a separate follow-up.
  • CodeRabbit threads 4127325782 (replay order for the cutover), 4127649472 (stale SPEC listings), 4136593714 (propagate a failed skip-record write) and 4136954925 (resolve pending broker hedges before the manual cover): addressed. The code, SPEC.md and the PR description's deploy step match the fixes described in each thread.

I found no new defects in the a110b1b..acdd113 diff. The deploy step (pause orders, resolve broker hedges, flatten each legacy symbol with a zero adjustment) is in both SPEC.md and the PR description. When I checked, the backend build CI job was still running; every other check had passed.

@JuaniRios

Copy link
Copy Markdown
Collaborator Author

@rain-marvin approve

@rain-marvin

rain-marvin Bot commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

🔎 Verifying that my findings from a110b1b are addressed at acdd113, started by @JuaniRios. The review will appear here when it's done.

@rain-marvin rain-marvin Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Opus 5.5 (Claude 1)

This PR converts Raindex fills of ERC-4626 wrapped equities into underlying broker-share units before Position accounting and hedging. Onchain inventory stays in wrapped shares, and each fill stores its proven ratio. In P&L, legacy symbols stay unavailable until a zero manual adjustment proves the position was flat.

Since a110b1b there is one commit, acdd113. It makes two changes:

  • normalized_fill_economics now maps a zero wrapper ratio to ZeroUnderlyingAmount. A fill on a drained wrapper now takes the per-fill skip, before the trading-disabled path, in both the worker and process-tx. It no longer fails as a process-scoped Ratio error on every retry.
  • The P&L unpriced-adjustment guard now runs inside the cutover candidate loop and follows the replay's price rules. A rejected candidate falls through to the next zero adjustment. The rejection warning names the blocking row and says to hedge at the broker before the new zero adjustment.

I checked that the guard scans only rows after the candidate, which matches the retain step (it keeps rows at or after the cutover). Only an onchain fill or a priced nonzero adjustment counts as a price, the same as replay.rs. CI is green at this head. I found no new defects in this diff.

Earlier findings:

  • The two gaps noted in the last review (the guard not matching the replay's price rules, and the guard not trying a later cutover): resolved in acdd113, as described above, with tests priced_zero_cutover_does_not_price_a_later_unpriced_adjustment and unpriced_adjustment_rejects_a_cutover_and_a_later_zero_adjustment_recovers.
  • Zero ratio escalating as a process-scoped error: resolved. The ratio is checked before UnderlyingPerWrapped::new, and zero_wrapper_ratio_fill_is_skipped_and_acknowledged tests it.
  • Warning text not naming the blocking row: resolved.

Threads resolved by hand:

  • 4128201006 (cutover crossing cases): addressed in part. The inverse crossing is fixed and tested. The dismissal of case 2 holds: a fill racing a later manual adjustment already mis-replays on master for every symbol, whatever its wrapped basis. It should get its own follow-up issue.
  • 4137136443 (a zero-underlying skip hidden behind an earlier decode-time row): addressed. record_skipped_fill lets ZeroUnderlyingAmount replace a decode-time row and keeps its detail. It never replaces trading_disabled, and a test covers both cases.
  • 4137136450 (unpriced adjustment after the cutover failing the whole report): addressed. Only that symbol becomes unavailable. Not carrying the dropped legacy price is correct, because that price has unknown basis.
  • 4137544344 (unpriced check not trying a later cutover): addressed in the candidate loop, with a test.

No open findings remain.

@JuaniRios
JuaniRios force-pushed the rai-2666-normalize-wrapped-equity-fills branch from acdd113 to a03d211 Compare September 29, 2026 21:18
@JuaniRios

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@JuaniRios
JuaniRios force-pushed the rai-2666-normalize-wrapped-equity-fills branch from a03d211 to 740ede7 Compare September 29, 2026 22:49
@JuaniRios

Copy link
Copy Markdown
Collaborator Author

Heads up for reviewers: in 740ede7 I changed how P&L treats fills recorded before this PR, per Juan's call. They keep counting 1:1 in wrapped shares, as they do on master, and the report warns when a range includes them. I dropped the "unavailable until a zero-adjustment cutover" approach and everything around it: the cutover candidate rules, capital suppression, and the dashboard banner.

Why: the old approach blanked all P&L history for every symbol to avoid SGOV's pre-merge error, which is about 1%. For every ratio-1 wrapper, the 1:1 figures were already exact. New fills still store their ratio and are exact. Hedging is unchanged.

The per-fill ratio storage and ledger migration stay. The deploy no longer needs a flatten, so the rollout in the description is now "deploy after close". The SGOV residual fix (about 15.7 shares short) is optional.

@JuaniRios

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@JuaniRios

Copy link
Copy Markdown
Collaborator Author

@rain-marvin review

@rain-marvin

rain-marvin Bot commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

🔎 Reviewing 740ede7, started by @JuaniRios. The review will appear here when it's done.

@coderabbitai

coderabbitai Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@rain-marvin rain-marvin Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Opus 5.5 (Claude 1)

This PR converts each wrapped (ERC-4626) Raindex fill into underlying broker shares, at the wrapper ratio of the fill's block, before it updates the Position and hedges. Onchain inventory stays in wrapped shares, the ratio is stored with each fill, a fill that converts to zero underlying shares is skipped per fill, and process-tx shares the same path.

Since the last review (acdd113), the branch was rebased onto the current master and the P&L design changed: the zero-adjustment cutover and the unavailable-symbol handling are gone. Fills recorded before this change now count 1:1 in wrapped shares, with a warning. That is exact for every ratio-1 wrapper and about 1% off for pre-merge SGOV, as the description says.

I traced the hedge, Position, inventory, cover-instruction and process-tx paths again at 740ede7. All of them use the right units, and the fixes from the earlier threads are still in place after the rebase. No blocking issue. Two minor points: the new legacy warning shows on every report for good, and no test covers a legacy lot matched against a new fill at a ratio other than 1.

The panel ran with two models. The other lanes could not authenticate and were dropped.

Comment thread src/dashboard/pnl/builder.rs
Comment thread src/dashboard/pnl/tests.rs
@JuaniRios
JuaniRios force-pushed the rai-2666-normalize-wrapped-equity-fills branch from 740ede7 to ab5eba9 Compare September 29, 2026 23:13
@JuaniRios

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@JuaniRios

Copy link
Copy Markdown
Collaborator Author

@rain-marvin approve

@coderabbitai

coderabbitai Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@rain-marvin

rain-marvin Bot commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

🔎 Verifying that my findings from a110b1b are addressed at ab5eba9, started by @JuaniRios. The review will appear here when it's done.

@rain-marvin rain-marvin Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Opus 5.5 (Claude 1)

This PR converts Raindex fills of ERC-4626 wrapped equities (for example SGOV) into underlying broker-share units before Position accounting and hedging. Onchain inventory stays in wrapped shares, and each fill stores its proven ratio.

The branch was rebased onto master (#1543, #1557, #1576, #1573). I compared the PR's own patch before and after the rebase. The shared files (SPEC.md, src/api.rs, src/operator.rs, src/rebalancing/trigger/mod.rs) only changed in SPEC.md, where the text now follows the new P&L design.

The main change since a110b1b is a simpler P&L design. The zero-adjustment cutover, the per-symbol "unavailable" state, and the capital suppression are all gone. Legacy fills that have no ratio now count 1:1 in wrapped shares, as before, and the report warns only when the queried range holds such a fill for a symbol whose recorded ratios are not all exactly 1. The warning compares against RATIO_ONE.to_string(), and that matches how the ledger stores the ratio (U256 in decimal). The dashboard, the response DTO, and the capital path no longer refer to unavailable symbols anywhere. This removes a lot of edge-case code that my earlier threads kept finding problems in. The remaining legacy error is small, bounded by the ratio minus 1, and it affects only the P&L display. Hedging does not depend on it.

One more change: a zero wrapper ratio at the fill block now takes the per-fill ZeroUnderlyingAmount skip. Before, UnderlyingPerWrapped::new returned an error and the fill failed on every retry. A new test covers the skip and the acknowledgement.

Earlier findings:

  • My last review (a110b1b) approved with no blocking findings. Its two minors are resolved.
  • Thread 4139160365 (legacy-ratio warning on every report): resolved. It now fires only for a legacy fill inside the range, and skips symbols proven 1:1. Tests: legacy_fill_outside_the_range_raises_no_warning and legacy_fill_on_a_proven_one_to_one_wrapper_raises_no_warning. The reply leaves out the "legacy lot still open at range start" part, so a range that starts after a legacy SGOV buy and closes that lot gets a slightly wrong realized figure with no warning. The error is bounded and affects display only, and the main complaint (noise) is fixed, so I accept that.
  • Thread 4139160371 (no test for a legacy lot matched against a new fill at a ratio other than 1): resolved. legacy_wrapped_lot_matches_a_new_underlying_fill_at_ratio_above_one pins realized -5, an open short of 0.1, no reconciliation note, and the SGOV warning.

Threads resolved by hand:

  • 4128201006: addressed. Case 1 was fixed earlier. Case 2 is an ordering problem that already exists on master, split out as a follow-up. The cutover code is now removed.
  • 4137136443: addressed. ZeroUnderlyingAmount replaces an earlier decode-time skip row and keeps its detail, but never replaces trading_disabled. A test covers both cases.
  • 4137136450 and 4137544344: no longer apply. The cutover and unpriced-adjustment logic they covered is removed, so a cutover can no longer fail the whole report on an unpriced adjustment.

No new defects in the delta. CI was still re-running at the time of this review. The failed run was a cancelled, superseded run, not a code failure.

@graphite-app

graphite-app Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Merge activity

  • Sep 30, 12:04 AM UTC: JuaniRios added this pull request to the Graphite merge queue.
  • Sep 30, 12:04 AM UTC: CI is running for this pull request on a draft pull request (#1580) due to your merge queue CI optimization settings.
  • Sep 30, 12:19 AM UTC: Merged by the Graphite merge queue via draft PR: #1580.

@graphite-app graphite-app Bot closed this Sep 30, 2026
@graphite-app
graphite-app Bot deleted the rai-2666-normalize-wrapped-equity-fills branch September 30, 2026 00:19
@github-actions github-actions Bot added the externally-merged Added to a PR that appears closed but is actually merged by an external actor like Graphite label Sep 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

externally-merged Added to a PR that appears closed but is actually merged by an external actor like Graphite

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants