feat(quoter-bot): make playground previews readable - #185
Merged
Conversation
Amounts render in whole loan-asset units from one decimals box, defaulting to 6 for USDC and falling back to exact raw integers when cleared. A quoter process has a single LOAN_ASSET_ADDRESS, so one scale covers both collections; the exact raw integer stays on hover. Each entry now reports the reference band it tolerates, swept from the config through the runtime's own generateLadderWithDiagnostics, with a response strip under each ladder plot. This answers what the deterministic preview cannot: the synthetic reference always lands mid-bounds, which for a ladder spanning its full half-range is the single rate at which no rung pins. Tiles reuse the editor field labels and print their config keys. Two labels contradicted their own help text and were corrected: offerSize was "Pending-offer cap" though it bounds one offer, and acceptanceAssets was "Completion threshold" though it is the shortfall. Bootstrap plot markers are labelled on the plot, and the ladder centre marker matches bootstrap's "Quote". Exports, the fragment codec, import parsing and validation are untouched: a differential run against main confirms all four outputs, the share URL and the fragment are byte-identical. autoRefill now defaults to true, the one deliberate change to emitted config. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Both plots now share one geometry: a vertical rate axis with the bounds labelled above and below, and one row per offer carrying its rate, a depth bar and its size. The ladder reads as price-level depth, and bootstrap as the single offer it publishes, sized against its credit target. Tile and helper text is anchored on the editor field labels, and the audit behind that corrected four ladder descriptions that misstated the runtime: sizeSkewBps compounds per step off a 10,000 BPS base rather than being a flat outer-versus-inner difference, an underfunded side drops its outermost rungs rather than its small ones, the exposure caps bound only the lending side, and movementToleranceBps gates recentring while a resize can still happen inside it. A derived reference outside the configured bounds no longer suppresses the preview. It renders with markers pinned to the axis and carries a notice saying so, because on the variable strategy that state is an artefact of the synthetic reference rather than an invalid config. A shape the shared parser genuinely rejects still cannot be drawn, so its message now restates the runtime's own inequality with the operator's numbers. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
thomas-chabert
marked this pull request as ready for review
August 31, 2026 09:49
Contributor
There was a problem hiding this comment.
Devin Review found 4 potential issues.
3 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)
…erence The runtime-preview parity smoke expected two preview errors for a collection whose synthetic reference leaves the plotted range. That suppression is exactly what this branch removed, so the assertion now requires zero errors, two notices, and both plots rendered — the contract it was written to protect, that a runtime-valid collection stays exportable.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c9abed7e23
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
thomas-chabert
requested review from
haydenshively
and
a lite review from Copilot
and removed request for
Copilot and
julien-devatom
August 31, 2026 10:07
Both bot reviewers landed on real problems in the preview, all of them cases where the page stated something the runtime does not do. Reference bands reported the first and last *sampled* clean rate as if exact. A stride above one BPS is reachable once the swept interval passes the sample cap, so a 0-20000 BPS range reported 19999 as its edge. The sweep now walks outward one BPS from each sampled edge, which costs at most one stride per side and makes the endpoints exact at any range. A maturity premium made both bands wrong: bootstrap ignored the premium and ladder pinned maturity at zero, so a band presented as general held only at maturity. Both callouts now say so. The ladder notice covered only the reference, leaving a premium-pushed centre visibly pinned with no explanation; it now names every marker the view can clamp, centre and far-maturity centre included. A hardcoded target was described as following the market across a band it can never traverse. The bootstrap offer row promised a raw amount on hover that only the ladder table carried. `acceptanceAssets` equal to `creditTarget` makes the runtime complete immediately and publish nothing, while the tile claimed one offer would fill it. `autoRefill: false` claimed it stops for good, though completion lives in an in-memory set a restart discards. Per repo utility isolation, the rung rendering helpers move out of the module holding ErrorBoundary into playground/rung-rendering.utils.tsx. Config output is unchanged: exports, fragment codec and validation stay byte-identical to main across the hardcoded strategy, per-book grouping and a zero accepted-credit target.
Devin's review covered more ground than the bootstrap row I had fixed: ladder plot sizes and rung hover text also showed only scaled amounts. Both now carry the raw integer, and the display-units promise is scoped to the plots and tables, which are the surfaces that actually honour it. Callout prose stays scaled-only, so it no longer claims otherwise.
julien-devatom
approved these changes
Sep 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The quoter-bot playground rendered every amount as a raw integer and drew rates on two unrelated plot styles. This makes it readable, and the audit behind it corrected several descriptions that misstated the runtime.
Readable amounts. One decimals box scales the whole page. A process has a single
LOAN_ASSET_ADDRESSand every configured amount is a raw smallest-unit amount of that one asset, so one scale is both sufficient and correct — collateral decimals never apply. Defaults to 6 for USDC, clears to exact raw integers, and every scaled amount keeps its raw value on hover.Both plots are order books. A vertical rate axis with the bounds labelled above and below, and one row per offer carrying its rate, a depth bar and its size. The ladder reads as price-level depth; bootstrap shows the single offer it publishes, sized against its credit target.
Tiles anchored on the editor vocabulary, each printing the config keys it derives from. Tiles with no keys are fixed runtime behaviour, which makes the distinction visible. Two editor labels contradicted their own help text and were corrected:
offerSizewas "Pending-offer cap" though it bounds one offer, andacceptanceAssetswas "Completion threshold" though it is the shortfall.Four ladder descriptions were wrong and are now derived from the code:
sizeSkewBpsminimumOfferAssetsaggregateBudgetfeedshigherBudget)movementToleranceBpsEach entry reports the reference band it tolerates, swept from the config through the runtime's own
generateLadderWithDiagnostics. This answers what a single deterministic preview cannot, since the synthetic reference always lands mid-bounds — for a ladder spanning its full half-range that is the one rate at which no rung pins.An out-of-range derived reference no longer suppresses the preview. It renders with markers pinned to the axis plus a notice, because on the variable strategy that state is an artefact of the synthetic reference, not an invalid config — exports stayed valid throughout. A shape the shared parser genuinely rejects still cannot be drawn, so its message now restates the runtime's own
sideWidth * 2 > rangeinequality with the operator's numbers.Config safety
Every change is display-only, with one deliberate exception:
autoRefillnow defaults totruefor new bootstrap entries.Verified by running this branch and
mainside by side over the same configs (variable and hardcoded strategies,shared-rungandper-book, with and without a maturity premium):16/17 identical, fragments compatible in both directions. Structurally, the JSON scanner, import parsing, fragment codec, all four exports and validation have zero changed lines.
Review round
Devin and Codex both reviewed
c9abed7; every posted finding was verified against the code and fixed inbf2ff8eandfd6f98f. All 11 threads resolved.acceptanceAssetsequal tocreditTargetmakes the runtime complete immediately and publish nothing, while the tile claimed one offer would fill it.autoRefill: falseclaimed it stops for good, though completion lives in an in-memory set a restart discards.ErrorBoundaryintoplayground/rung-rendering.utils.tsx.Config output stayed byte-identical to
mainthroughout, re-verified across the hardcoded strategy,per-bookgrouping and a zero accepted-credit target. Four new tests cover the copy corrections.Three further Devin findings are hidden by repository review settings and are not visible through the API — they remain unaddressed and can be seen in Devin Review.
Checks
tsc --noEmitclean;oxlint0 warnings / 0 errors across 599 files;oxfmtclean;knipreports no unused playground exportsvitest run— 2597 passed, 11 skipped. 14 test files fail to collect (unbuilt@repo/contractsin three other bots, plus two fork e2e tests needing a Base RPC); the identical 14 fail onorigin/main, diff emptycheck-jsdocflags 482 items repo-wide, none inplayground/Not verified locally
Local Node is 24.5.0 against the pinned
^24.14.1, so installs and runs used--config.engine-strict=false.playground:smoke:testcannot run on macOS at all — both the wrapper and the smoke script callassertProcessInspection, which refuses on any non-Linux platform ("Definitive descendant cleanup requires Linux /proc process inspection"). CI is therefore the only place it executes, and its first run here caught a stale assertion: the runtime-preview parity scenario expected two preview errors for a runtime-valid collection whose synthetic reference leaves the plotted range, which is exactly the suppression this branch removes. That assertion now requires zero errors, two notices and both plots rendered — the property it was written to protect. Fixed in e5a7601; all checks green.Two other selectors the suite depends on were updated with the behaviour change: the ladder centre marker label is now
Quote, and.ladder-reference-markeris scoped to[data-preview="ladder"]since bootstrap now has one too.🤖 Generated with Claude Code