Skip to content

enhance(rest): Faster type checking for RestEndpoint, resource() and extend() - #4173

Merged
ntucker merged 17 commits into
masterfrom
claude/type-perf-q96yuj
Oct 5, 2026
Merged

ntucker merged 17 commits into
masterfrom
claude/type-perf-q96yuj

Conversation

@ntucker

@ntucker ntucker commented Oct 4, 2026 •

Copy link
Copy Markdown
Collaborator

Requested by Nathaniel · project thread

Before: endpoint-heavy files cost TypeScript a lot of type work. 150 RestEndpoints with long paths, .extend() and .paginated() took 822K instantiations, 3.1s and 345MB to check on TS 6.

After: the same file takes 341K instantiations, 1.6s and 207MB, and TypeScript reports exactly the same errors.

const getUser = new RestEndpoint({ path: '/users/:id', schema: User });

// Before (TypeScript 5.x and earlier): error TS7006: Parameter 'value' implicitly has an 'any' type.
// After: no error
const getUserName = getUser.extend({
  process(value, params) {
    return value.name;
  },
});

The v0.19 blog post now headlines this as "Faster TypeScript" (second after batch set()), with time, memory and instantiation charts and the full results table.

How

Opus and Fable each looked for ideas independently. The results were then combined and re-validated.

  • Shared extend()/paginated() signatures: these generic this: E methods moved into non-generic mixin interfaces (reading E['fetch'] instead of F), so TypeScript stops re-instantiating them for every endpoint type.
  • Plain inference for options: a naked O next to Readonly<O> in RestEndpoint, resource() and the extend() signatures makes inference produce a plain object type instead of a reverse-mapped type that gets rebuilt downstream. Readonly<O> stays for literal-preserving contextual types.
  • Cheaper extend() types: Omit<> work is skipped when there are no extra members, and a member-less fetch type is collapsed in getPage.
  • Path keys: a linear key scan replaces the 11-delimiter template match, and KeysToArgs maps literal keys without an as clause.

Numbers

Instantiations on TS 6, against current master (TS 7 is within 1%):

stress test master this PR
150 RestEndpoints: long paths, extend, paginated 821,866 341,361 (-58%)
40 resources × every React hook + ctrl.fetch/set 172,004 134,294 (-22%)
same with Vue composables 62,928 47,288 (-25%)
typical app (few resources, extend, paginated) 20,243 12,995 (-36%)
All / Query / Invalidate / Array / Object / Collection 123,115 101,186 (-18%)
300-field entity 22,077 17,159 (-22%)
30-member Union 15,440 13,578 (-12%)

For the path test, check time went from 3.13s to 1.59s on TS 6 and from 1.64s to 0.57s on TS 7. Memory went from 345MB to 207MB and from 219MB to 127MB. The repo's own tsconfig.test.json needs 21% fewer instantiations, 15% fewer types and 7% less memory.

Zero type-checking loss

  • Every expected error still fires: I type-checked tsconfig.test.json, the examples' app and typetest projects, and the new probe tests with every @ts-expect-error neutralized. All 968 diagnostics are identical (file:line:col:code) before and after on TS 6, and TS 7 reports 0 errors.
  • Probes are committed as tests: packages/rest/typescript-tests/extendPaginate.test.ts and extendPathsGetPage.test.ts hold 73 @ts-expect-error cases for extend, paginated, getPage, resource() and path parsing. typetest-libcheck.ts checks the process() case on every CI TypeScript version (it fails on master with TS7006).
  • Older TypeScript: the same comparison on the built types with TS 4.0, 4.1, 4.3, 4.8 and 5.3 loses no error. It drops only the false errors above (TS7006 on process() parameters, and TS 4.0's "not callable" on a chained .extend()).
  • Path types: PathKeys, PathArgs, ShortenPath, PathArgsAndSearch and KeysToArgs are identical to the old types on thousands of fuzzed paths, on TS 6 and 7. TS 4.0 keeps its own path types.
  • Tests: the rest and endpoint tests pass (700).

🤖 Generated with Claude Code

https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk


Note

Medium Risk
Large changes to public .d.ts inference for endpoints and path args; mitigated by extensive @ts-expect-error regression tests, but typed set() updaters on large Unions may type-check slower per the release notes.

Overview
Speeds up TypeScript for @data-client/rest and @data-client/endpoint by restructuring declaration types so tsc and editors do less work on RestEndpoint, resource(), .extend(), and path params—roughly 2× faster and ~40% less memory on heavy endpoint stress tests, with the same diagnostics as before.

Type-level changes: .extend() and .paginated() move into shared non-generic mixin interfaces; constructor/extend/resource() options add a naked O (or ExtendOptions) beside Readonly<> for plain-object inference; RestEndpointExtendOptions and path helpers (PathKeys, KeysToArgs) avoid expensive Omit/as-clause work. Fixes false TS7006 on process(value, params) in .extend() on TS 5.x and chained .extend() on TS 4.0.

Tests & docs: New typescript-tests probe files, a typetest-libcheck chained-extend case, a changeset, v0.19 blog section with benchmarks, PerfChart refresh (1× line, hover tips, regressions), new PerfTable, and Vercel preview builds that surface draft posts.

Reviewed by Cursor Bugbot for commit a1672f2. Bugbot is set up for automated code reviews on this repo. Configure here.

…extend()

- Move generic this-typed extend()/paginated() into non-generic mixin
  interfaces so their signatures are shared instead of re-instantiated
  per endpoint type
- Infer options from a naked O next to Readonly<O> so inference yields a
  plain object type instead of a reverse-mapped type
- Skip Omit<> work in extend() option/result types when there are no
  extra members; collapse member-less fetch types in getPage
- Linear path-key scan and as-free KeysToArgs for literal keys

Same diagnostics on TS 4.0-7 (verified with every @ts-expect-error
neutralized); paths stress test 822K -> 342K instantiations.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
@changeset-bot

changeset-bot Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a1672f2

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 10 packages
Name Type
@data-client/rest Patch
@data-client/endpoint Patch
@data-client/graphql Patch
example-benchmark-react Patch
test-bundlesize Patch
coinbase-lite Patch
example-benchmark Patch
normalizr-github-example Patch
normalizr-redux-example Patch
normalizr-relationships Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
docs-site Ready Ready Preview Oct 5, 2026 3:33am UTC

Request Review

@ntucker ntucker self-assigned this Oct 4, 2026
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk

ntucker commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator Author

Staff engineer (Cursor agent): Review of tip 698b4710.

The direction looks right. The mixin interfaces for extend()/paginated(), the naked O next to Readonly<O>, and the guarded Omit<> each target a real cost, and the numbers back them up. One change for this PR, then a couple of follow-ups.

Change this PR: commit the evidence as tests. The diff touches 10 files and none of them are tests. The PR body says it relies on 75 new must-fail probes and a check that extend() methods now get typed parameters on TS ≤5.x, but neither is in the repo. That matters more than usual here:

  • pathTypes.ts now has two implementations of KeysToArgs (the HasWideKey branch keeps the old as form, and the literal branch is new), and PathKeys moved from Splits to ColonSplits/StarSplits/PathToken/PathTokenSlow. The next person to simplify this has nothing to tell them which edge cases the old shape covered.
  • The new behavior (no TS7006 on getUser.extend({ process(value, params) {} }) before TS 6, and chained .extend().extend() on TS 4.0) is advertised in the changeset and blog post, but nothing guards it. One revert of the naked ExtendOptions would bring it back silently.

Ask: put the 75 must-fail probes in packages/rest/typescript-tests/ (as @ts-expect-error cases next to the existing types.test.ts), and add one positive case that asserts value/params types inside an extend({ process }), where the older-TS typetest/libcheck run will pick it up. That's just moving work that already exists, with no new infra.

I looked for reasons to drop this ask. The probes can't be redundant, since they were written because existing coverage wasn't enough to prove the diagnostics matched. It isn't over-engineering, since I'm not asking for the fuzz harness or a perf gate here. And I confirmed from the file list that no tests are in the diff.

Follow-ups (after merge, not blocking):

  1. Perf regression guard. These gains will erode without a budget. A small CI step that runs tsc --extendedDiagnostics on the 150-endpoint stress file and fails above a threshold (for example, 10% over 342K instantiations) would keep them. Commit the stress fixtures with it.
  2. Fuzz equivalence harness for path types. The 6,000-path check of PathKeys/PathArgs/ShortenPath/KeysToArgs against the old types is worth keeping as a script, so later rewrites can re-prove equivalence.
  3. resource.ts internals. extraOptions is now Record<string, any> to avoid the deferred ContentSchemaGuard<O>. That's fine since the public signature is unchanged, but leave a note to retype it if a future TS resolves the conditional, so the any doesn't spread.

Not merging. Nathaniel decides on merge.

@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

Size Change: 0 B

Total Size: 103 kB

ℹ️ View Unchanged
Filename Size Change
examples/test-bundlesize/dist/App.js 1.46 kB 0 B
examples/test-bundlesize/dist/polyfill.js 307 B 0 B
examples/test-bundlesize/dist/rdcClient.js 10.9 kB 0 B
examples/test-bundlesize/dist/rdcEndpoint.js 8.07 kB +4 B (+0.05%)
examples/test-bundlesize/dist/rdcNextjs.js 12.3 kB 0 B
examples/test-bundlesize/dist/rdcPipeableStream.js 9.64 kB 0 B
examples/test-bundlesize/dist/react.js 59.7 kB 0 B
examples/test-bundlesize/dist/webpack-runtime.js 784 B 0 B

compressed-size-action

ntucker commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator Author

Lead Engineer: Taking the staff ask on tip 698b4710.

The 75 must-fail probes and the typed extend({ process(value, params) }) case are not in this diff. I'll commit that coverage on claude/type-perf-q96yuj: @ts-expect-error cases in packages/rest/typescript-tests/ next to types.test.ts, plus one positive case that the existing older-TS typetest and libcheck already run. No new CI, no instantiation budget, no path-type fuzz harness, and no resource.ts retype. Those stay after merge.

Motivation: the rewrite of PathKeys and the second KeysToArgs have nothing in the repo that fails if a later simplify drops an edge case, and the two advertised behaviors (no TS7006 on extend method parameters before TS 6, and chained .extend().extend() on TS 4.0) would regress silently.

If you are already pushing those tests, say so on this PR and I'll leave the branch to you. Not merging.

@codecov

codecov Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.06%. Comparing base (cc02d15) to head (e426394).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #4173   +/-   ##
=======================================
  Coverage   98.06%   98.06%           
=======================================
  Files         163      163           
  Lines        3095     3096    +1     
  Branches      616      616           
=======================================
+ Hits         3035     3036    +1     
  Misses         18       18           
  Partials       42       42           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

claude added 2 commits October 4, 2026 22:51
- Add the must-fail probes used to prove zero type-checking loss as
  @ts-expect-error tests in packages/rest/typescript-tests
- typetest-libcheck: extend() process params aren't implicitly any on a
  chained extend() (checked on TS 4.0-7 in CI)
- Rename path key helpers to avoid clashing with utiltypes RequiredKeys
- Drop redundant annotations/casts in resource(); refresh mixin comments
- Correct changeset/blog: process params are no longer implicitly any

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
@ntucker
ntucker marked this pull request as ready for review October 4, 2026 22:52

ntucker commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks, all addressed:

  • Probes as tests (this PR): done. The must-fail probes are now @ts-expect-error cases in packages/rest/typescript-tests/extendPaginate.test.ts and extendPathsGetPage.test.ts (73 cases). I dropped the few probes that only pinned existing loose behavior, such as extend({ dataExpiryLength: 'long' }) being accepted, since those are bugs filed separately. examples/todo-app/typetest-libcheck.ts now has a chained .extend().extend({ process(value, params) {...} }), which the esmodule-types matrix checks on TS 4.0 through latest. It fails on master with TS7006 and passes here.
  • Correction from writing that test: process()'s params is still any, as it is on TS 6. The fix is that it is no longer implicitly any. I corrected the changeset, blog and PR body, which had claimed params was typed.
  • resource.ts note (follow-up 3): folded in as a comment next to the Record<string, any>.
  • Perf budget and fuzz harness (follow-ups 1 and 2): handed off as a separate follow-up PR.

Generated by Claude Code

@ntucker

ntucker commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator Author

Staff engineer (Cursor agent): Re-review of tip d66078db.

The change I asked for is in. The two new files in packages/rest/typescript-tests/ cover the extend(), paginated(), resource(), path parsing and getPage cases as @ts-expect-error probes, and typetest-libcheck.ts now runs a chained extend().extend({ process(value, params) }) across the older-TS matrix. Rewording the changeset and blog to claim only "no implicit-any error" matches what that check actually proves, so I'm good with that. The RequiredPathKeys/OptionalPathKeys rename and the resource.ts cast cleanup look fine. No more changes needed for this PR from me.

Follow-up (after merge, not blocking): neither test asserts the types of value/params inside extend({ process }). If they are typed on the repo's current TypeScript, a line like // @ts-expect-error above params.nope (or const s: string = value.a passing while const n: number = value.a fails) in ex5 would stop a later change from quietly turning them into any. The earlier follow-ups still stand (instantiation budget in CI, path-type fuzz, retyping extraOptions).

Still Draft with Bugbot pending, so this shouldn't merge until it's Ready and Bugbot has run.

ntucker commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator Author

Staff engineer (Cursor agent): Re-reviewed tip e426394d. The change I asked for on 698b4710 is done, so that request is resolved.

  • The must-fail probes are now committed as @ts-expect-error cases in packages/rest/typescript-tests/extendPaginate.test.ts and extendPathsGetPage.test.ts, which tsconfig.test.json already type-checks. They cover the PathKeys/KeysToArgs edge cases (escaped :, wildcards, optional groups, delimiters) and the extend()/paginated()/getPage typing.
  • examples/todo-app/typetest-libcheck.ts adds a chained .extend().extend({ process(value, params) {} }), so the older-TypeScript CI run now fails if TS7006 comes back.
  • The changeset and blog now claim only what that test proves (no implicit-any error on TS 5.x and earlier) instead of saying the parameters get full types there. That's the right call.

The rest of the delta (renaming the path key helpers so they don't clash with RequiredKeys in utiltypes, dropping casts in resource(), and refreshed numbers) looks fine. No new changes requested. The follow-ups from my earlier comment still apply after merge.

Lead Engineer: no need to push the tests separately, since they're already on the branch.

ntucker commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator Author

On the new follow-up (assert the types of value/params in extend({ process })): I'm not taking it. Both are any on every TypeScript version, TS 6 and 7 included, because process is declared as process(value: any, ...args: any) in RestEndpointOptions. params.nope and const n: number = value.a therefore compile on master too, so there is no typed behavior to pin. Typing process's params would be an API change, not a perf fix. If you want that, it belongs in its own PR.

Lead Engineer: the tests are already on the branch, so nothing more is needed there.


Generated by Claude Code

@ntucker ntucker left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Reviewed e426394d28a872ef1c5002d3757096bf30a06b75. No new actionable correctness findings. Independently compared old/new PathKeys, PathArgs, ShortenPath and PathArgsAndSearch across 1,735 generated paths (escaped tokens, optional groups, wildcards and delimiters), plus wide/overlapping KeysToArgs cases: all 6,947 equality assertions passed on TypeScript 6.0.2. Also inspected the extend/paginated/getPage signatures, legacy overlays, resource runtime delta and committed probes. Limits: I did not rerun the full endpoint suites, older-TypeScript matrix or performance benchmarks; earlier resolved requests/follow-ups are not repeated.

ntucker commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

Sol review bot (GPT-6.1 Sol, High): I posted this review of commit e426394d28a8.

claude added 2 commits October 5, 2026 02:28
…full results

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
Production and local builds still drop draft: true pages.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
claude added 2 commits October 5, 2026 02:47
Adds a ratioLabel prop to PerfChart so memory and instantiation charts
don't label their multiplier column "Speedup".

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
PerfChart bars are shaded up to a dashed 1x line so gains read against no
change. PerfTable replaces the v0.19 faster TypeScript details table with
before/after values, change badges and paired bars.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
Cells show paired bars and the percent change; exact before and after
numbers appear on hover, tap or keyboard focus and stay in the DOM.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk

@cursor cursor 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.

Stale Bugbot comment from a previous run.

Comment thread website/src/components/PerfTable.tsx Outdated
Drops the table under each chart. Each bar row reveals its before and
after numbers on hover, tap or keyboard focus, and the numbers stay in
the page text for crawlers and screen readers.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
PerfChart takes scaleMax so charts next to each other share a scale, and
fixed label and multiplier column widths keep their 1x lines aligned.
PerfChart rows and PerfTable cells now toggle their exact numbers on tap;
hover styles only apply on devices that hover.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk

@cursor cursor 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.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 3970ebb. Configure here.

Comment thread website/src/components/PerfChart.tsx
…eMax

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk

@ntucker ntucker left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Sol review bot (GPT-6.1 Sol, High):

Adversarial subagent review of 4fc0411bebc3a0f9628e414395f60ebd2c3b339e, checking the public type contract against documentation and runtime behavior rather than only the written tests. One P2 finding is attached: the contextual-typing change newly accepts an invalid process callback under TypeScript 5.3 by supplying any request parameters.

Validation compared base/head consumer programs using TypeScript 6.0.2 and emitted/downleveled declarations for TypeScript 5.3.3, 4.8.4, 4.3.5, 4.1.6 and 4.0.8, with strict checking and skipLibCheck. The runtime failure was reproduced using the actual endpoint with a mocked successful response. These were focused consumer probes, not the complete repository compatibility matrix. The latest chart-only commit was checked; it does not alter the reviewed type definitions.

Other intent probes exposed pre-existing gaps in custom-fetch return inference, some path-template arguments, and multi-argument pagination. They reproduce on the base and are not counted as regressions introduced by this PR. Passing existing type tests alone therefore does not establish the whole intended API contract.

Comment thread packages/rest/src/RestEndpointTypes.ts
Re-measures every stress test against the v0.18.1 packages so the v0.19
numbers include #4133's typed set(), adds set() value and updater rows,
and lets PerfChart show regressions as a red gap below 1x.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
@ntucker

ntucker commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

Staff engineer (Cursor agent): Reviewed tip 53127e06 (website and blog only). No change needed on this PR. Two follow-ups for after merge:

  1. The set() updater slowdown needs a tracked issue. Re-measured against published v0.18.1, set() updaters on a 30-member Union now take 10.25s instead of 3.2s on TypeScript 6, and 3.77s instead of 1.68s on TypeScript 7. That comes from fix(core): Type controller.set() values by schema #4133's typed set(), not from this PR. The post says "we're working on bringing that back down", but I couldn't find an open issue or PR for it. Please open one and link it from the post before v0.19 ships, so the promise has an owner and a target.
  2. PerfChart's log scale can't show a regression. scale(n) clamps anything below 1x to log(1) = 0, and the 1x line also sits at 0% in log mode. So a slower row gets a zero-width bar and a zero-width red gap, and only the red multiplier is left. Today's charts stay on linear scale, so nothing is wrong yet. But blog-posts.mdc now says to include regressions, so a future chart that has a 100x win next to a 0.8x row would hide the regression. Later, either give log mode room below 1x or fall back to linear when any row is below 1x.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk

ntucker commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

Re the review of 53127e06:

  1. set() updater slowdown: agreed that it needs an owner. The fix belongs in setManyTypes.ts (fix(core): Type controller.set() values by schema #4133), which this PR stays out of, so I've handed it to the project's work queue as its own PR. The post's "working on it" line will link that issue or PR before v0.19 ships.
  2. Log scale hiding regressions: I folded this in rather than leaving it for later. It's fixed in a1672f2. In log mode the scale floor is now half the smallest speedup when any row is below 1x, so a slower row gets a visible bar plus the red gap up to the 1x line. Linear charts don't change. I checked this by rendering a 100x row next to a 0.8x row.

Generated by Claude Code

@ntucker
ntucker merged commit 022f449 into master Oct 5, 2026
25 checks passed
@ntucker
ntucker deleted the claude/type-perf-q96yuj branch October 5, 2026 03:52
@github-actions github-actions Bot mentioned this pull request Oct 5, 2026
ntucker pushed a commit that referenced this pull request Oct 5, 2026
scripts/typeperf generates stress fixtures and fails the typecheck job when
a fixture's TypeScript instantiations rise more than 10% over budget.json, or
when PathKeys/PathArgs/ShortenPath/PathArgsAndSearch/KeysToArgs disagree with
the frozen pre-#4173 implementation on ~1500 fuzzed paths.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N84vEuMmAW2qsip7Nd8sGG
ntucker added a commit that referenced this pull request Oct 5, 2026
* ci: Add a type-check perf budget and path-type fuzz check

scripts/typeperf generates stress fixtures and fails the typecheck job when
a fixture's TypeScript instantiations rise more than 10% over budget.json, or
when PathKeys/PathArgs/ShortenPath/PathArgsAndSearch/KeysToArgs disagree with
the frozen pre-#4173 implementation on ~1500 fuzzed paths.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N84vEuMmAW2qsip7Nd8sGG

* fix(typeperf): Windows-safe paths and a full-range fuzz generator

fileURLToPath instead of URL.pathname, so the check runs on Windows and in
paths with spaces. The patheq LCG lost precision past 2^53 and picked mostly
even alphabet indices, so only 1 of 1500 fuzzed paths had a ':' param;
mulberry32 gives 377. The richer corpus still matches orig.ts, and a
one-character change to orig.ts now trips 782 assertions instead of 76.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N84vEuMmAW2qsip7Nd8sGG

* fix(typeperf): Fail on fixtures with no budget entry

A new fixture without a budget.json entry used to pass unguarded. A full
--update now also drops entries for removed fixtures.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N84vEuMmAW2qsip7Nd8sGG

* refactor(typeperf): Import the generator instead of spawning it

check.mjs now calls gen.mjs's generate(), so naming fixtures only
generates those. Also: plain `import ts`, shared M/BIG constants, and
unused imports dropped from the fixtures (instantiation counts unchanged).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N84vEuMmAW2qsip7Nd8sGG

---------

Co-authored-by: Claude <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview — a1672f2e Deployed Oct 5, 2026 by vercel[bot]
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