DX-050/061/072/075: versioned docs routing, page feedback, funding-and-fees, unified-liquidity - #642
Merged
IbrahimIjai merged 5 commits intoAug 31, 2026
Conversation
…O4-Markets#587, SO4-Markets#584) Rewrites the funding-and-fees stub into a full page enumerating all five client-computed costs (position fee, price impact, funding, borrow fee, execution fee), each traced to its source in apps/web/src/features/trade, with a computed multi-interval worked example and an explicit "where the client diverges from the contracts" section (flat price impact, an unused borrow-fee estimate, a hard-coded fee config). Adds /concepts/unified-liquidity explaining the single-pool-per-market model, what a depositor is exposed to without euphemism, and how pool composition caps available leverage per side — grounded in SyntheticsReader's getMarketPoolValueInfo/getOpenInterest and the same availableLiquidity formula used in useMarketsInfo.ts. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WTKBjRjyEgeAPpw33XVfZZ
Discovered while writing the funding-and-fees/unified-liquidity pages, both of which mention DataStore, ExchangeRouter, and SyntheticsReader — bun run lint hung indefinitely rather than completing. Root cause: REQUIRED_CAPITALIZATIONS' four hyphenated-term entries (order-vault, exchange-router, synthetics-reader, data-store) used only the /i flag, not /g. The check loop resets a global regex's lastIndex and calls exec() in a while loop, but a non-global regex's exec() ignores lastIndex and always returns the same first match, so the loop over any line containing one of these terms never terminated. Existing pages already use all four terms throughout apps/docs/content/reference, so this hung on unrelated, previously-merged content too, not just this branch's new pages. Adding /g fixes the hang. With the linter able to actually finish, it surfaced a second bug: the same four checks never exempted inline code spans or link destinations (the function's own comment already said "Skip if matched inside link or code snippet" — that exemption was never implemented), so every correctly-lowercase route link or file-path mention in the whole content tree (e.g. `data-store.ts`, [/reference/synthetics-reader](/reference/synthetics-reader)) was flagged as a capitalization error. Added maskCodeAndLinks to blank those spans before the capitalization check runs, preserving column numbers for everything else. After both fixes, 12 genuine pre-existing violations remained in bare prose across 5 files this PR does not otherwise touch (local-setup.mdx, security.mdx, troubleshooting.mdx, order-vault.mdx, synthetics-reader.mdx) — "just"/"simply" and two real DataStore/OrderVault capitalization misses. Fixed those too with minimal word-level edits, since bun run lint must pass for this PR to be committable at all and leaving them red for unrelated reasons was not an option; no other content in this PR needed changes. Regression tests added: one confirming the linter terminates on content using all four hyphenated terms, one confirming code spans/link destinations are exempt while bare-prose mentions still correctly fail. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WTKBjRjyEgeAPpw33XVfZZ
…ts#573, SO4-Markets#562) Cookieless "was this helpful" feedback (DX-061): - src/lib/feedback.ts validates and redacts a submission (Stellar/Soroban strkeys, EVM addresses, 32-byte hex, emails) down to exactly four stored fields: path, verdict, redacted comment, and a day-granularity timestamp. No cookie, identifier, or IP is ever read or stored. - routes/api/feedback.post.ts is the storage endpoint, registered explicitly in nitro.config.ts rather than picked up by file-based scanning — this app never sets serverDir, so that scan doesn't run (see the comment on /old-path in the same file, which is the only other evidence this matters: it's the sole reason that route works either). Explicit registration also means this handler can't rely on Nitro's auto-imported globals, so it imports defineEventHandler/readBody/ setResponseStatus from h3 and useStorage from nitro/storage directly. - public/assets/feedback-widget.js is a plain external script (the docs CSP is script-src 'self' with no unsafe-inline, so no inline handler is possible) that rate-limits by page per session via sessionStorage (wrapped in try/catch throughout) and never surfaces a submission failure to the reader. - Verified against the built server directly: 204 on a valid submission with no set-cookie header, 400 on a bad verdict or a missing path. Versioned documentation routing (DX-050): - src/lib/doc-versions.ts is pure route arithmetic: versionedRoute prefixes a route for a given version (current stays unprefixed, unchanged from DX-029), and resolveVersionSwitchTarget picks the exact page in the target version, falling back to that version's same-labelled section's first page, then to that version's home. - scripts/snapshot-version.ts copies content/ into content-versions/<id>/ — an exact, disposable snapshot. content-versions/ is git-ignored; nothing here ships a real second version yet, per the issue's scope (ship exactly one version now). - build.ts now also builds any content-versions/<id>/ directory under an explicit /<id> prefix, with a noindex tag, a visible archived-version banner, and no data-pagefind-body (pagefind skips a page entirely once any page on the site has that attribute, which is how every archived page is excluded from search without a separate allow/deny list). A version picker renders in the header once more than one version exists, with each option's target precomputed at build time. - Proved the mechanism locally: ran snapshot-version.ts v0, rebuilt, and confirmed /v0/concepts/risk exists with noindex + banner, the picker on both /concepts/risk and /v0/concepts/risk cross-links correctly, and pagefind indexed 33 of 66 built pages (the current version only) — then deleted the snapshot per the issue's instruction not to commit it. scripts/content.ts gains loadPagesFrom(root) (parsePage's route computation now takes an optional root, defaulting to contentRoot) so build.ts can load both content/ and each content-versions/<id>/ with the same code path. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WTKBjRjyEgeAPpw33XVfZZ
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WTKBjRjyEgeAPpw33XVfZZ
|
@precious-akpan is attempting to deploy a commit to the Ijai's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
@precious-akpan Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
4 tasks
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.
Summary
Resolves four assigned issues on one branch:
/concepts/funding-and-fees/concepts/unified-liquidityDocs content (#587, #584)
/concepts/funding-and-feesfrom a 12-line stub into a full page enumerating all five costs a position can accrue (position fee, price impact, funding, borrow fee, network/execution fee), each traced to the actual client code (useTradeFees.ts,data-store.ts,useFundingRate.ts,trade-math.ts) with file paths, plus a computed multi-interval worked example. It also has an honest "where the client diverges from the contracts" section: price impact is a flat rate rather than size/imbalance-dependent, the borrow fee is configured in two disagreeing places and isn't applied to any total or shown in the trade panel, andfetchFeeConfigdoesn't actually read fromDataStoredespite its name./concepts/unified-liquidityexplaining the single-pool-per-market model, what a depositor is exposed to without euphemism, and how pool composition caps available leverage per side — grounded inSyntheticsReader.getMarketPoolValueInfo/getOpenInterestand the sameavailableLiquidityformulauseMarketsInfo.tsalready uses.concepts/unified-liquiditytocontent/meta.json.Feedback widget (#573)
src/lib/feedback.ts: validates a submission and redacts anything shaped like a Stellar/Soroban strkey, an EVM address, a 32-byte hex string, or an email, down to exactly four stored fields — path, verdict, redacted comment, day-granularity timestamp. No cookie, identifier, or IP is ever read.routes/api/feedback.post.ts: the storage endpoint, backed bynitro/storage'suseStorage.public/assets/feedback-widget.js: an external script (the docs CSP isscript-src 'self'with nounsafe-inline, so no inline handler is possible) that rate-limits by page per session viasessionStorage, wrapped intry/catchthroughout, and never surfaces a submission failure to the reader. Rendered at the foot of every page frombuild.ts.204on a valid submission with noset-cookieheader,400on a bad verdict or a missing path (seescripts/feedback-endpoint.test.ts).Versioned routing (#562)
src/lib/doc-versions.ts: pure route arithmetic. Current version stays unprefixed (unchanged from DX-029).resolveVersionSwitchTargetpicks the exact page in the target version if it exists, else the same-labelled section's first page in that version ("that version's section index"), else that version's home.scripts/snapshot-version.ts: copiescontent/intocontent-versions/<id>/, an exact disposable snapshot.content-versions/is git-ignored — nothing here ships a real second version, per the issue's scope ("ship exactly one version now").build.tsnow also builds anycontent-versions/<id>/directory under an explicit/<id>prefix, with anoindextag, a visible archived-version banner, and nodata-pagefind-body(pagefind skips a page entirely once any page on the site has that attribute — that's how archived pages are excluded from search with no separate allow/deny list needed). A version picker renders in the header once more than one version exists; each option's destination is precomputed at build time.snapshot-version.ts v0, rebuilt, and confirmed/v0/concepts/riskexists withnoindex+ banner, the picker on both/concepts/riskand/v0/concepts/riskcross-links correctly, and pagefind indexed 33 of 66 built pages (current version only). Then deleted the snapshot.Bugs found and fixed along the way
Both discovered because the new content pages mention
DataStore/ExchangeRouter/SyntheticsReader, which existing reference pages already do too:lint-prose.tshung indefinitely.REQUIRED_CAPITALIZATIONS's four hyphenated-term checks used/iwithout/g; a non-global regex's.exec()ignoreslastIndexand always returns the same match, sowhile (exec() !== null)never terminated on any line mentioningorder-vault/exchange-router/synthetics-reader/data-store— which is most ofcontent/reference/*. This meansbun run lint(and thereforebun run build, which shells out to it) has been hanging onmainalready, independent of this PR, whenever run against that content. Fixed by adding/g.data-store.ts,[/reference/synthetics-reader](/reference/synthetics-reader), etc.) — the function's own comment already said "Skip if matched inside link or code snippet," but that exemption was never implemented. AddedmaskCodeAndLinksto blank inline code spans and link targets before the capitalization check runs.local-setup.mdx,security.mdx,troubleshooting.mdx,order-vault.mdx,synthetics-reader.mdx) — banned words ("just"/"simply") and two realDataStore/OrderVaultcapitalization misses. Fixed with minimal word-level edits, sincebun run linthas to pass for this PR to be committable at all./api/feedbackto my handler at all — it silently fell through to the SPA'sindex.htmlwith a200, for every request including malformed ones. Root cause: this app never setsserverDir, so Nitro 3's file-based route-scanning (scanServerRoutes) never runs;/old-pathonly works today because it's registered explicitly innitro.config.ts'shandlersarray, not because file-based routing works. Registered/api/feedbackthe same explicit way, and switched the handler to explicith3/nitro/storageimports instead of relying on auto-imported globals (which apparently only get injected for scanned routes, not explicitly-registered ones).Regression tests for (1) and (2) are in
scripts/lint-prose.test.ts.Pre-existing, out-of-scope failures found but not fixed
Running the full commit gate surfaced several failures unrelated to any of these four issues, predating this branch. Flagging them rather than silently expanding scope:
apps/web/src/features/changelog/components/ChangelogPage.tsx:184has a genuine syntax error (Declaration or statement expected) that breaksweb's lint, typecheck, and build entirely. This alone means the rootbun lint/bun typecheck/bun run buildcannot pass right now regardless of this PR.apps/docsis missingvitest,vitest-axe,@testing-library/user-event, andmswas declared dependencies, breakingDocsHome.test.tsx,content-checker.test.ts,shortcuts.test.ts, andsearch.test.tsx(all pre-existing files this PR doesn't touch).scripts/seo.test.tsimports ascripts/lib/og-generatormodule that doesn't exist.scripts/components.test.tsxhas two pre-existing failures (Sidebar/Pager active-link assertions).check:tokensreports a false positive —apps/docs/src/styles/{globals,print}.csscontain the literal comment text "issue DX-063: Add a print stylesheet for documentation pages #575", which the raw-hex-color regex matches as if#575were a color — plus one genuine arbitrary-value violation inSidebar.tsx(text-[10px]). Neither file is touched by this PR..changelog/unreleased/538-docs-workspace.mdpredates the current entry schema (hastitle/categoryinstead oftype/area/pr/breaking) and failschangelog:validate.scripts/search.test.ts's "generates deterministic index" test times out at its 15s budget in this sandbox (it runs two full Vite builds sequentially); it passed the equivalent checks when I ran the underlying build directly.Test plan
All run from
apps/docsunless noted.bun run scripts/lint-prose.ts— 0 errors (93 pre-existing sentence-length warnings, non-blocking)bun run check:content/check:links— pass, 35 pages, zero orphans, zero broken linksbun test src/lib/feedback.test.ts src/lib/doc-versions.test.ts— 46/46 pass (new)bun test scripts/nitro.test.ts scripts/feedback-endpoint.test.ts— 7/7 passbun test(full apps/docs suite) — 100/111 pass; all 11 fail + 3 errors are the pre-existing, unrelated files listed abovebun run build(apps/docs, includesnitro build) — succeeds/api/feedback:204valid,400bad verdict,400missing path, noset-cookiebun run --cwd apps/docs typecheck— 7 pre-existing errors, none touch any file this PR creates or modifiesbun lint/bun typecheck/bun run test/bun run build— all fail on the pre-existing, unrelatedapps/websyntax error and/or the pre-existingapps/docsgaps listed above;docs's own portion of each passes standalone as shown🤖 Generated with Claude Code
https://claude.ai/code/session_01WTKBjRjyEgeAPpw33XVfZZ