Skip to content

feat(quoter-bot): make playground previews readable - #185

Merged
thomas-chabert merged 5 commits into
mainfrom
feature/quoter-bot-playground-readability
Sep 1, 2026
Merged

feat(quoter-bot): make playground previews readable#185
thomas-chabert merged 5 commits into
mainfrom
feature/quoter-bot-playground-readability

Conversation

@thomas-chabert

@thomas-chabert thomas-chabert commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

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_ADDRESS and 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: offerSize was "Pending-offer cap" though it bounds one offer, and acceptanceAssets was "Completion threshold" though it is the shortfall.

Four ladder descriptions were wrong and are now derived from the code:

Was Actually
sizeSkewBps flat outer-vs-inner difference compounds per step off a 10,000 BPS base
minimumOfferAssets "small rungs are dropped" an underfunded side drops its outermost rungs
exposure caps bound the market bound the lending side only (aggregateBudget feeds higherBudget)
movementToleranceBps suppresses republishing gates recentring; a resize still happens inside it

Each 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 > range inequality with the operator's numbers.

Config safety

Every change is display-only, with one deliberate exception: autoRefill now defaults to true for new bootstrap entries.

Verified by running this branch and main side by side over the same configs (variable and hardcoded strategies, shared-rung and per-book, with and without a maturity premium):

SAME  exportBootstrapJson          SAME  encodePlaygroundFragment
SAME  BOOTSTRAP_MARKETS            SAME  createPlaygroundShareUrl (with query)
SAME  exportLadderJson             SAME  new code decodes main fragment
SAME  LADDER_MARKETS               SAME  main code decodes new fragment
SAME  parseCollectionsImport ×2    SAME  maturity premium fragment
SAME  validatePlaygroundState      SAME  validateBootstrapCollection
SAME  validateLadderCollection     SAME  createDefaultLadder
DIFFERS createDefaultBootstrap  →  autoRefill false → true (intended)

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 in bf2ff8e and fd6f98f. All 11 threads resolved.

  • Reference bands reported sampled edges as 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 boundary. The sweep now walks outward one BPS from each sampled edge — one stride per side at most, exact at any range.
  • A maturity premium made both bands wrong. Bootstrap ignored the premium, ladder pinned maturity at zero, so a band shown 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.
  • A hardcoded target was described as market-following across a band it can never traverse.
  • Raw amounts were promised but not delivered outside the ladder table. Bootstrap and ladder plot amounts and rung hover text now carry them; the promise is scoped to plots and tables, since callout prose stays scaled-only.
  • 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.
  • Utility isolation: rung rendering helpers moved out of the module holding ErrorBoundary into playground/rung-rendering.utils.tsx.

Config output stayed byte-identical to main throughout, re-verified across the hardcoded strategy, per-book grouping 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 --noEmit clean; oxlint 0 warnings / 0 errors across 599 files; oxfmt clean; knip reports no unused playground exports
  • vitest run — 2597 passed, 11 skipped. 14 test files fail to collect (unbuilt @repo/contracts in three other bots, plus two fork e2e tests needing a Base RPC); the identical 14 fail on origin/main, diff empty
  • check-jsdoc flags 482 items repo-wide, none in playground/
  • 73 playground tests, including two new suites for the amount formatter and the reference sweep

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:test cannot run on macOS at all — both the wrapper and the smoke script call assertProcessInspection, 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-marker is scoped to [data-preview="ladder"] since bootstrap now has one too.

🤖 Generated with Claude Code

thomas-chabert and others added 2 commits August 31, 2026 11:02
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
thomas-chabert marked this pull request as ready for review August 31, 2026 09:49

@devin-ai-integration devin-ai-integration 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.

Devin Review found 4 potential issues.

3 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)

Devin Review

Comment thread bots/quoter-bot/playground/reference-response.utils.ts
Comment thread bots/quoter-bot/playground/model.ts
Comment thread bots/quoter-bot/playground/model.ts Outdated
Comment thread bots/quoter-bot/playground/app.tsx Outdated
…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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 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".

Comment thread bots/quoter-bot/playground/reference-response.utils.ts
Comment thread bots/quoter-bot/playground/reference-response.utils.ts
Comment thread bots/quoter-bot/playground/app.tsx Outdated
Comment thread bots/quoter-bot/playground/model.ts Outdated
Comment thread bots/quoter-bot/playground/model.ts Outdated
Comment thread bots/quoter-bot/playground/model.ts Outdated
Comment thread bots/quoter-bot/playground/app.tsx Outdated
@thomas-chabert
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.
@thomas-chabert
thomas-chabert merged commit 28aad60 into main Sep 1, 2026
5 checks passed
@thomas-chabert
thomas-chabert deleted the feature/quoter-bot-playground-readability branch September 1, 2026 12:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants